drop image (or click)
HTML
<div class="filedrag" style="width: 500px;">
<label class="filedrag-filename"></label>
<img class="filedrag-preview" src="img/placeholder.gif">
<div> </div>
<div class="filedrag-droparea">drop image (or click)</div>
<div class="filedrag-progress"></div>
<input type="file" class="filedrag-input" id="file-input" name="file-input">
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
JavaScript
// Based on https://www.sitepoint.com/html5-ajax-file-upload/ (but heavily modified)
var MAX_FILE_SIZE = 33554432; //32MB
function parseFile(file, image_target, callback) {
//Basic file type validation
if (file.type !== 'image/jpeg' && file.type !== 'image/png' && file.type !== 'image/gif') {
alert('Invalid image type. Valid formats: jpg, gif, png');
return false;
}
//File size validation
if (file.size > MAX_FILE_SIZE) {
alert('File is too large. Max file size: ' + MAX_FILE_SIZE);
return false;
}
//Toss an image preview in there right from the client-side
var reader = new FileReader();
reader.onload = function (e) {
image_target.siblings('.filedrag-preview').attr('src', e.target.result);
image_target.siblings('filedrag-filename').html(file.name);
}
reader.readAsDataURL(file);
window[callback];
}
function uploadFile(file, post_target, input_id, onComplete) {
var xhr = new XMLHttpRequest();
var response = null;
//Create progress bar
$(".filedrag-progress").html('<p>Uploading...</p>');
//Update progress bar
xhr.upload.addEventListener("progress", function (e) {
var pc = parseInt(100 - (e.loaded / e.total * 100));
$(".filedrag-progress p").css("backgroundPosition", pc + "% 0");
}, false);
//Upload finished
xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
$(".filedrag-progress p")
.addClass("success")
.html("Success!")
.fadeOut('slow', function () {
$(".filedrag-progress p")
.html("")
.removeClass("success");
});
if (!xhr.responseText) {
$('.filedrag-filename').html('Error fetching post response');
return false;
}
response = JSON.parse(xhr.responseText);
response.input_id = input_id;
if (onComplete) {
window[onComplete](response);
}
} else {
$('.filedrag-filename').html('Error posting image');
return false;
}
}
};
//Start the upload
xhr.open("POST", post_target + "/filetype/" + file.type.replace("image/", ""), true);
xhr.setRequestHeader("X-FILENAME", file.name);
xhr.send(file);
}
function initUploaders(post_target, onComplete) {
var xhr = new XMLHttpRequest();
//Only do this stuff if the technology is supported
if (xhr.upload) {
var dropArea = $('.filedrag-droparea');
var dragAreaInput = $('.filedrag-input');
//Handle the dragover event
dropArea.on("dragover", function (e) {
e.stopPropagation();
e.preventDefault();
if (!$(this).hasClass('hover')) {
$(this).addClass('hover');
}
});
//And the dragleave event
dropArea.on("dragleave", function (e) {
e.stopPropagation();
e.preventDefault();
if ($(this).hasClass('hover')) {
$(this).removeClass('hover');
}
});
//A file was dragged onto the droppable area, do stuff
dropArea.on("drop", function (e) {
//Prevent bubbling or default browser handling of image drag/drop
e.stopPropagation();
e.preventDefault();
//Disable hover state
if ($(this).hasClass('hover')) {
$(this).removeClass('hover');
}
//Fetch the images from the FileList object
var files = e.originalEvent.dataTransfer.files;
//We'll return this in the response, because it comes in handy sometimes
var input_id = $(this).siblings('.filedrag-input').attr('id');
// process all File objects
for (var i = 0, f; f = files[i]; i++) {
parseFile(f, $(this));
uploadFile(f, post_target, input_id, onComplete);
}
});
dropArea.on("click", function (e) {
$(this).siblings('.filedrag-input').trigger('click');
});
//Handle file select
dragAreaInput.change(function (e) {
var files = e.target.files;
//We'll return this in the response, because it comes in handy sometimes
var input_id = $(this).siblings('.filedrag-input').attr('id');
// process all File objects
for (var i = 0, f; f = files[i]; i++) {
parseFile(f, $(this));
uploadFile(f, post_target, input_id, onComplete);
}
});
//Show the drag and drop area
dropArea.show();
dragAreaInput.hide();
}
}
function responseCallback(response) {
console.log(response);
}
$(function () {
initUploaders('accept-input.php', 'responseCallback');
});
SCSS
.filedrag-droparea {
display: none;
font-weight: bold;
text-align: center;
padding: 1em 0;
margin: 1em 0;
color: #555;
border: 2px dashed #555;
border-radius: 7px;
cursor: default;
}
.filedrag-droparea.hover {
color: #f00;
border-color: #f00;
border-style: solid;
box-shadow: inset 0 3px 4px #888;
}
.filedrag-preview {
max-width: 100%;
}
.filedrag-progress p {
display: block;
width: 240px;
padding: 2px 5px;
margin: 2px 0;
border: 1px inset #446;
border-radius: 5px;
background: #eee url(img/progress.png) 100% 0 repeat-y;
}
.filedrag-progress p.success {
background: #0c0 none 0 0 no-repeat;
}
.filedrag-progress p.failed {
background: #c00 none 0 0 no-repeat;
}
PHP: accept-input.php
<?php
$fn = ($_SERVER['HTTP_X_FILENAME'] ?? false);
$types = array('image/png', 'image/jpeg', 'image/gif');
$extensions = array('png', 'jpg', 'gif');
$maxsize = 1024 * 1024; // 1MB
$okToUpload = false;
/**
* We will respond with json with a key of input_id if successful
*
* @param $input_id
* @param $message
*
* @return void
*/
function respondAndExit($input_id, $message)
{
echo json_encode(
array(
'input_id' => $input_id,
'message' => $message
)
);
exit();
}
if ($fn) :
if (in_array($_SERVER['CONTENT_TYPE'], $types)
&& in_array(pathinfo($fn, PATHINFO_EXTENSION), $extensions)
&& $_SERVER['CONTENT_LENGTH'] <= $maxsize
) {
file_put_contents(
'uploads/' . $fn,
file_get_contents('php://input')
);
// echo "$fn uploaded";
respondAndExit('fileselect', "$fn uploaded");
} else {
respondAndExit('fileselect', "Invalid file");
}
else:
// form submit
$files = $_FILES['fileselect'];
foreach ($files['error'] as $id => $err) {
if ($err == UPLOAD_ERR_OK) {
$fn = $files['name'][$id];
move_uploaded_file(
$files['tmp_name'][$id],
'uploads/' . $fn
);
}
}
respondAndExit('fileselect', "File uploaded");
endif;