I am trying to implement Dropzone JS to help with uploading files to the server. I'm using a generic implementation of Dropzone on the client side with my html looking like this:
<form id='portfolioupload' action='PortfolioUpload.php' class='dropzone'>
<div class='fallback'>
<input name='file' type='file' />
</div>
</form>
In the server, I do some checks and, in the end, I rename the file and move it into it's final place:
$newname = substr(GetGUID(false), -7) . '.' . $ext;
move_uploaded_file($_FILES['file']['tmp_name'], PortfolioPath() . $newname)
I pass this information back using json, as suggested in Dropzone.js- How to delete files from server?:
header_status(200); // output header, error 200
echo json_encode(array("Filename" => $newname));
The code sample there looks like it adds it to an array that can be passed to the server for deletion. So close, but not quite what I'm looking for.
I then stumble on the question, how to upload and delete files from dropzone.js, and see that I can listen to the removedfile event. So I implement the code there like so:
Dropzone.options.portfolioupload = {
acceptedFiles: '.png, .jpg, .gif',
addRemoveLinks: true,
maxFiles: 25,
maxFilesize: 500000,
removedfile: function(file) {
alert('Deleting ' + file.name);
var name = file;
$.ajax({
type: 'POST',
url: 'app/assets/PortfolioUpload.php',
data: "f=delete&fn="+name,
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
};
The request is sent to the server successfully except that the filename is that of the original, not the server's renamed filename.
After scouring the net today I feel like I can't figure out how to tie the two items together. For example, if I uploaded foo.jpg and rename it in the server to dk03p7b.jpg, how do I tell Dropzone that foo.jpg = dk03p7b.jpg so that when the user clicks Remove file, it's also removed in the server?
I solved this myself by, first, taking the json from the success response and saving it to the element file.previewElement.id like this:
success: function( file, response ) {
obj = JSON.parse(response);
file.previewElement.id = obj.filename;
}
Then I use that value when doing the delete ajax call in the removedfile event:
removedfile: function(file) {
var name = file.previewElement.id;
$.ajax({
type: 'POST',
url: 'deletefile.php',
data: "fn="+name,
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
},
This also worked for me
// "myAwesomeDropzone" is the camelized version of the HTML element's ID
var myDropzone = new Dropzone("#myAwesomeDropzone", {
/*
* This step isn't required.
success: function(file, response) {
file.previewElement.id = response.id;
}
*/
});
myDropzone.on('removedfile', function(file) {
var id = jQuery(file.previewElement).find('.dz-filename span').html();
// directly access the removing preview element and get image name to delete it from server.
// var id = file.previewElement.id;
$.ajax({
type: 'POST',
url: '<?php echo base_url('seller/deleteImagegalleryById'); ?>',
data: {id: id, '<?php echo $this->security->get_csrf_token_name(); ?>': '<?php echo $this->security->get_csrf_hash(); ?>'},
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
});
Related
I want to implement a simple file upload in my intranet-page, with the smallest setup possible.
This is my HTML part:
<input id="sortpicture" type="file" name="sortpic" />
<button id="upload">Upload</button>
and this is my JS jquery script:
$("#upload").on("click", function() {
var file_data = $("#sortpicture").prop("files")[0];
var form_data = new FormData();
form_data.append("file", file_data);
alert(form_data);
$.ajax({
url: "/uploads",
dataType: 'script',
cache: false,
contentType: false,
processData: false,
data: form_data,
type: 'post',
success: function(){
alert("works");
}
});
});
There is a folder named "uploads" in the root directory of the website, with change permissions for "users" and "IIS_users".
When I select a file with the file-form and press the upload button, the first alert returns "[object FormData]". the second alert doesn't get called and the"uploads" folder is empty too!?
Can someone help my finding out whats wrong?
Also the next step should be, to rename the file with a server side generated name. Maybe someone can give me a solution for this, too.
You need a script that runs on the server to move the file to the uploads directory. The jQuery ajax method (running on the client in the browser) sends the form data to the server, then a script running on the server handles the upload.
Your HTML is fine, but update your JS jQuery script to look like this:
(Look for comments after // <-- )
$('#upload').on('click', function() {
var file_data = $('#sortpicture').prop('files')[0];
var form_data = new FormData();
form_data.append('file', file_data);
alert(form_data);
$.ajax({
url: 'upload.php', // <-- point to server-side PHP script
dataType: 'text', // <-- what to expect back from the PHP script, if anything
cache: false,
contentType: false,
processData: false,
data: form_data,
type: 'post',
success: function(php_script_response){
alert(php_script_response); // <-- display response from the PHP script, if any
}
});
});
And now for the server-side script, using PHP in this case.
upload.php: a PHP script that is located and runs on the server, and directs the file to the uploads directory:
<?php
if ( 0 < $_FILES['file']['error'] ) {
echo 'Error: ' . $_FILES['file']['error'] . '<br>';
}
else {
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']);
}
?>
Also, a couple things about the destination directory:
Make sure you have the correct server path, i.e., starting at the PHP script location what is the path to the uploads directory, and
Make sure it's writeable.
And a little bit about the PHP function move_uploaded_file, used in the upload.php script:
move_uploaded_file(
// this is where the file is temporarily stored on the server when uploaded
// do not change this
$_FILES['file']['tmp_name'],
// this is where you want to put the file and what you want to name it
// in this case we are putting in a directory called "uploads"
// and giving it the original filename
'uploads/' . $_FILES['file']['name']
);
$_FILES['file']['name'] is the name of the file as it is uploaded. You don't have to use that. You can give the file any name (server filesystem compatible) you want:
move_uploaded_file(
$_FILES['file']['tmp_name'],
'uploads/my_new_filename.whatever'
);
And finally, be aware of your PHP upload_max_filesize AND post_max_size configuration values, and be sure your test files do not exceed either. Here's some help how you check PHP configuration and how you set max filesize and post settings.
**1. index.php**
<body>
<span id="msg" style="color:red"></span><br/>
<input type="file" id="photo"><br/>
<script type="text/javascript" src="jquery-3.2.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$(document).on('change','#photo',function(){
var property = document.getElementById('photo').files[0];
var image_name = property.name;
var image_extension = image_name.split('.').pop().toLowerCase();
if(jQuery.inArray(image_extension,['gif','jpg','jpeg','']) == -1){
alert("Invalid image file");
}
var form_data = new FormData();
form_data.append("file",property);
$.ajax({
url:'upload.php',
method:'POST',
data:form_data,
contentType:false,
cache:false,
processData:false,
beforeSend:function(){
$('#msg').html('Loading......');
},
success:function(data){
console.log(data);
$('#msg').html(data);
}
});
});
});
</script>
</body>
**2.upload.php**
<?php
if($_FILES['file']['name'] != ''){
$test = explode('.', $_FILES['file']['name']);
$extension = end($test);
$name = rand(100,999).'.'.$extension;
$location = 'uploads/'.$name;
move_uploaded_file($_FILES['file']['tmp_name'], $location);
echo '<img src="'.$location.'" height="100" width="100" />';
}
Use pure js
async function saveFile()
{
let formData = new FormData();
formData.append("file", sortpicture.files[0]);
await fetch('/uploads', {method: "POST", body: formData});
alert('works');
}
<input id="sortpicture" type="file" name="sortpic" />
<button id="upload" onclick="saveFile()">Upload</button>
<br>Before click upload look on chrome>console>network (in this snipped we will see 404)
The filename is automatically included to request and server can read it, the 'content-type' is automatically set to 'multipart/form-data'. Here is more developed example with error handling and additional json sending
async function saveFile(inp)
{
let user = { name:'john', age:34 };
let formData = new FormData();
let photo = inp.files[0];
formData.append("photo", photo);
formData.append("user", JSON.stringify(user));
try {
let r = await fetch('/upload/image', {method: "POST", body: formData});
console.log('HTTP response code:',r.status);
alert('success');
} catch(e) {
console.log('Huston we have problem...:', e);
}
}
<input type="file" onchange="saveFile(this)" >
<br><br>
Before selecting the file Open chrome console > network tab to see the request details.
<br><br>
<small>Because in this example we send request to https://stacksnippets.net/upload/image the response code will be 404 ofcourse...</small>
var formData = new FormData($("#YOUR_FORM_ID")[0]);
$.ajax({
url: "upload.php",
type: "POST",
data : formData,
processData: false,
contentType: false,
beforeSend: function() {
},
success: function(data){
},
error: function(xhr, ajaxOptions, thrownError) {
console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
}
});
and this is the php file to receive the uplaoded files
<?
$data = array();
//check with your logic
if (isset($_FILES)) {
$error = false;
$files = array();
$uploaddir = $target_dir;
foreach ($_FILES as $file) {
if (move_uploaded_file($file['tmp_name'], $uploaddir . basename( $file['name']))) {
$files[] = $uploaddir . $file['name'];
} else {
$error = true;
}
}
$data = ($error) ? array('error' => 'There was an error uploading your files') : array('files' => $files);
} else {
$data = array('success' => 'NO FILES ARE SENT','formData' => $_REQUEST);
}
echo json_encode($data);
?>
I'm trying to provide data to my MYSQL Database using Ajax, however, for some reason my PHP file is not reading the JSON array that I post to the file. Within the array I also have a file to store an image on my server as well as my database.
Javascript file
$(document).ready(function(){
// Give Data to PHP
// process the form
$('form').submit(function(event) {
// get the form data
// there are many ways to get this data using jQuery (you can use the class or id also)
//formData.append('tax_file', $('input[type=file]')[0].files[0]
var img = $('input[name=img]').prop('files')[0];
var name = img.name,
tmp = img.tmp_name,
size = img.size,
form = $('input[name=form-submit]').val(),
myName = $('input[name=my-name]').val(),
desc = $('input[name=description]').val();
// document.write(name + tmp + size);
var formData = {
'form-submit' : form,
'my-name' : myName,
'description' : desc,
'img' : name,
'tmp_name' : tmp,
'size' : size
};
// document.write(JSON.stringify(formData));
console.log(formData);
// process the form
$.ajax({
url : 'insert-bio.php', // the url where we want to POST
type : 'POST', // define the type of HTTP verb we want to use (POST for our form)
data : formData, // our data object
processData : false,
contentType : false,
dataType : 'json', // what type of data do we expect back from the server
encode : true
})
// using the done promise callback
.done(function(data) {
// log data to the console so we can see
console.log(data);
// here we will handle errors and validation messages
});
// stop the form from submitting the normal way and refreshing the page
event.preventDefault();
});
});
My PHP file
include('../db.php');
$conn = new Database();
echo explode(",", $_POST['data']);
if(isset($_POST['form-submit'])){
// text data
$name = strip_tags($_POST['my-name']);
$desc = strip_tags($_POST['description']);
// picture stuff
$file = rand(1000,100000)."-".$_FILES['img']['name'];
$file_loc = $_FILES['img']['tmp_name'];
$file_size = $_FILES['img']['size'];
$file_type = $_FILES['img']['type'];
// folder for profile pic
$folder = "bio-pic/";
// new file size in KB
$new_size = $file_size/1024;
// make file name in lower case
$new_file_name = strtolower($file);
// final pic file
$final_file=str_replace(' ','-',$new_file_name);
// mysql query for form data
if(move_uploaded_file($file_loc,$folder.$final_file)){
$sql="INSERT INTO bio(img, name, description) VALUES('$final_file', '$name', '$desc')";
$conn->query($sql);
}
} else {
echo "Need data";
}
$query = $conn->query("SELECT * FROM bio");
$results=$query->fetchAll(PDO::FETCH_ASSOC);
$parse_bio_json = json_encode($results);
file_put_contents('bio-DATA.json', $parse_bio_json);
echo $parse_bio_json;
The console shows that I have made contact with my PHP file, but it simply has not read any data.
The error on the PHP file:
Notice: Undefined index: data in /Applications/XAMPP/xamppfiles/htdocs/WEBSITE/BIO/insert-bio.php on line 8
Notice: Array to string conversion in /Applications/XAMPP/xamppfiles/htdocs/WEBSITE/BIO/insert-bio.php on line 8 ArrayNeed data[]
I had the same issue back in the day. After doing lots of research I found out that JSON cannot have a property that holds a file value. However, you can follow this example. It worked great for me. Hope it helps :)
$('#upload').on('click', function() {
var file_data = $('#sortpicture').prop('files')[0];
var form_data = new FormData();
form_data.append('file', file_data);
alert(form_data);
$.ajax({
url: 'upload.php', // point to server-side PHP script
dataType: 'text', // what to expect back from the PHP script, if anything
cache: false,
contentType: false,
processData: false,
data: form_data,
type: 'post',
success: function(php_script_response){
alert(php_script_response); // display response from the PHP script, if any
}
});
});
PHP
<?php
if ( 0 < $_FILES['file']['error'] ) {
echo 'Error: ' . $_FILES['file']['error'] . '<br>';
}
else {
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']);
}
?>
Credit goes to -> jQuery AJAX file upload PHP
Hi Guys I have the following function that is called on a link:onclick(), but for some reason the $.ajax does nothing at all - have even stripped my php code to only dump the $_POST var but I still get no feedback from the function - all i get is the alert msg - which is also just there for test purposes...
called there:
Save
function saveMyGame(){
var usern = $('#usern').attr('value');
var usrPoints = $('#userPoints').attr('value');
var usrLevel = $('#userlevel').attr('value');
var saveState = this.imgPath;
alert('Saving your game: '+usern+' Points: '+usrPoints+' Level: '+usrLevel+' state phase: '+saveState);
e.preventDefault();
var svGame = {act:'saveGame',user:usern, Points:usrPoints, Level:usrLevel, saveGState:saveState} ;
$.ajax({
url: "game/lib/updateGame.php",
type: "POST",
cache: false,
data: svGame,
dataType: "html",
success: function(svGame) {
$(".traget").html(svGame).fadeIn('slow');
}
});
}
the PHP code is suppose to check act, then verify that all required info is passed, than process the request or display an error msg...
<?php
if(isset($_POST['act']) && $_POST['act'] == 'saveGame') {
//Process save game request
/*if(isset($_POST['user']) && isset($_POST['userPoints']) && isset($_POST['userLevel']) && isset($_POST['saveGState']) ) {
$Game->saveGame();
echo'<br>....'.$_POST['user'];
} else {
echo 'Please provide correct information for saving...';
}
*/
echo var_dump($_POST);
}
Url in your ajax request has relative path url: "game/lib/updateGame.php", without slash in the beginning of the url like url: "/game/lib/updateGame.php",.
So maybe if your page adress differ from root (for example http://yourdomain.com/games/), full path will be http://yourdomain.com/games/game/lib/updateGame.php and therefore the server method is not performed.
I have used the below code the image has been deleted but the thumbnail image still showing.
Dropzone.options.myDropzone = {
init: function() {
this.on("success", function(file, response) {
file.serverId = response;
});
this.on("removedfile", function(file) {
if (!file.serverId) { return; }
$.post("delete-file.php?id=" + file.serverId);
});
}
For deleting thumbnails you have to enable
addRemoveLinks: true,
and to use "removedfile" option in dropzonejs
removedfile: Called whenever a file is removed from the list. You can listen to this and delete the file from your server if you want to.
addRemoveLinks: true,
removedfile: function(file) {
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
I also added an ajax call for delete script and it looks like this:
addRemoveLinks: true,
removedfile: function(file) {
var name = file.name;
$.ajax({
type: 'POST',
url: 'delete.php',
data: "id="+name,
dataType: 'html'
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
It works on my side, so I hope it helps.
In addition to the best answer above - to remove spaces and replace with dashes and convert to lower case apply this js in the dropzone.js file:
name = name.replace(/\s+/g, '-').toLowerCase();
To the filename handling - I edited the dropzone.js file AND the above ajax call. This way, the client handles the file naming, and it AUTOMATICALLY gets sent to the PHP/server-side, so u don't have to redo it there, and it's URL safe pretty much.
In some instances the js changed depending on the function / naming:
dropzone.js - line 293 (approx):
node = _ref[_i];
node.textContent = this._renameFilename(file.name.replace(/\s+/g, '-').toLowerCase());
dropzone.js - line 746 (approx):
Dropzone.prototype._renameFilename = function(name) {
if (typeof this.options.renameFilename !== "function") {
return name.replace(/\s+/g, '-').toLowerCase();
}
return this.options.renameFilename(name.replace(/\s+/g, '-').toLowerCase());
};
I moved the whole removedFile section up to the top of dropzone.js like so:
autoQueue: true,
addRemoveLinks: true,
removedfile: function(file) {
var name = file.name;
name =name.replace(/\s+/g, '-').toLowerCase(); /*only spaces*/
$.ajax({
type: 'POST',
url: 'dropzone.php',
data: "id=" + name,
dataType: 'html',
success: function(data) {
$("#msg").html(data);
}
});
var _ref;
if (file.previewElement) {
if ((_ref = file.previewElement) != null) {
_ref.parentNode.removeChild(file.previewElement);
}
}
return this._updateMaxFilesReachedClass();
},
previewsContainer: null,
hiddenInputContainer: "body",
Note I also added in a message box in the html: (div id="msg"></div>) in the HTML that will allow server side error handling/deleting to post a message back to the user as well.
in dropzone.php:
if (isset($_POST['id']) {
//delete/unlink file
echo $_POST['id'] . ' deleted'; // send msg back to user
}
This is only an expansion with the working code on my side. I have 3 files, dropzone.html, dropzone.php, dropzone.js
Obviously, you would create a js function instead of repeating the code, but it suited me since the naming changes. You could pass the variables in a js function yourself to handle filename spaces/chars / etc.
jQuery-File-Upload
Upload script:
$('#fileupload').fileupload({
url: 'api/combox_upload.php',
type: 'POST',
dataType: 'json',
dropZone: $dropZone,
singleFileUploads: true,
done: function (e, data) {
attachments = attachments.concat(data.result);
refreshAttachments();
},
add: function(e, data) {
var file = data.files[0];
data.context =
$('<li>',{'class':'file-upload-item'})
.append($('<span>').text(file.name))
.append(
$('<div>',{'class':'progressbar'})
.append($('<div>',{'class':'progress'}))
).appendTo($fileUploads);
data.submit(); // start upload immediately
},
progress: function(e, data) {
var progress = data.loaded / data.total;
data.context.find('.progress').stop().animate({'width':(progress*100)+'%'},100,'linear');
//data.context.find('.progress').css({'width':(progress*100)+'%'});
}
});
In my api/combox_upload.php script I echo json_encode($_FILES) and half the time it comes back blank (I'm watching the XHR request responses in Chrome developer toolbar).
Why is that? How do I fix it so it always submits the file?
Edit: It seems to happen more frequently with larger files.
Could it be an issue with PHP not handling multipart data correctly? I noticed the XHR request comes in immediately, as soon as the file upload begins, but PHP obviously hasn't gotten the whole file yet... so what does it do? Does it block when I try to access the $_FILES object or does it just give me an empty array? Do I have to something special?
Through trial and error I discovered that this problem only occurs with files larger than about 23 MiB. I'm not sure if that's a universal constant or specific to how my server is configured.
Nevertheless, I figured out how to get around this limitation. You need to set singleFileUploads to true and multipart to false, e.g.
$('#fileupload').fileupload({
url: 'api/upload.php',
type: 'POST',
dataType: 'json',
singleFileUploads: true,
multipart: false,
...
And then in your php script you can read in the data like this:
$handle = fopen('php://input', 'r');
$file_data = '';
while(($buffer = fgets($handle, 4096)) !== false) {
$file_data .= $buffer;
}
fclose($handle);
The $_FILES array will still be empty, so you can't get the filename out of there, but it seems to be set in the Content-Disposition header. I wrote a regex to pull it out:
$headers = getallheaders();
$filesize = strlen($file_data);
if(isset($headers['Content-Disposition']) && preg_match('`\bfilename="((?:\\.|[^"])*)"`',$headers['Content-Disposition'], $m)) {
$filename = urldecode($m[1]);
} else {
$filename = 'unknown';
}