I am using the following plugin: http://tutorialzine.com/2013/05/mini-ajax-file-upload-form/
The problem I have is that I have multiple upload instances on the same page (for example 1-header image 2-footer image)
But only the first input actually works, the other one does not and I don't get an error client or server side..
If I Google to try find an alternative I get millions of "multiple uploads at the same time" which is not what im looking for.
here is the page code:
<form id='upload' method='post' action='URLtoServerside' enctype='multipart/form-data'>
<div id='drop'>
Drop Here
<a>Browse</a>
<input type='file' name='upl' multiple />
</div>
<input style='visibility:hidden' id='".$var2['id']."' value='page_session_weo' />
<ul style='display:none'>
<!-- The file uploads will be shown here -->
</ul>
</form>
<form id='upload' method='post' action='URLtoServerside' enctype='multipart/form-data'>
<div id='drop'>
Drop Here
<a>Browse</a>
<input type='file' name='upl' multiple />
</div>
<input style='visibility:hidden' id='".$var2['id']."' value='page_session_weo' />
<ul style='display:none'>
<!-- The file uploads will be shown here -->
</ul>
</form>
PHP Code:
$allowed = array('png');
if(isset($_FILES['upl']) && $_FILES['upl']['error'] == 0){
$extension = pathinfo($_FILES['upl']['name'], PATHINFO_EXTENSION);
if(!in_array(strtolower($extension), $allowed)){
echo '{"status":"error"}';
exit;
}
if(move_uploaded_file($_FILES['upl']['tmp_name'], 'images/'.$name.'.png')){
echo '{"status":"success"}';
exit;
}
}
echo '{"status":"error"}';
exit;
Can someone please either tell me how to get this to work with multiple uploads on the same page, or recommend an alternative.
(I do require drag and drop as well as 'browse' functionality)
<input type="button" name="button" value="添加附件" onclick="addInput()">
<span id="upload"></span>
js
<script type="text/javascript">
var attachname = "attach";
var i=1;
function addInput(){
if(i>0){
var attach = attachname + i ;
if(createInput(attach))
i=i+1;
}
}
function createInput(nm){
var aElement=document.createElement("input");
aElement.name=nm;
aElement.id=nm;
aElement.type="file";
aElement.size="50";
if(document.getElementById("upload").appendChild(aElement) == null)
return false;
return true;
}
I just came with this problem.
My solution:
I duplicate the script.js from miniupload with script2.js or whatever.
In that script, the only thing I did was changing name from upload to upload_files and drop to drop_files.
Like this:
var ul = $('#upload_files ul');
$('#drop_files a').click(function(){
// Simulate a click on the file input button
// to show the file browser dialog
$(this).parent().find('input').click();
});
// Initialize the jQuery File Upload plugin
$('#upload_files').fileupload({
(...)
My HTML:
<form id="upload" method="post" enctype="multipart/form-data">
<div id="drop" style="text-align:center ;align-content:center">
Add images
<a>Select</a>
<input type="file" name="upl" multiple />
</div>
<ul>
<!-- The img uploads will be shown here -->
</ul>
</form>
<form id="upload_files" method="post" enctype="multipart/form-data">
<div id="drop_files" style="text-align:center ;align-content:center">
Add files
<a>Select</a>
<input type="file" name="upl_file" multiple />
</div>
<ul>
<!-- The file uploads will be shown here -->
</ul>
</form>
And then modify the css too.
the original css is like this:
#upload{
font-family:'PT Sans Narrow', sans-serif;
background-color:#373a3d;
background-image:-webkit-linear-gradient(top, #373a3d, #313437);
background-image:-moz-linear-gradient(top, #373a3d, #313437);
background-image:linear-gradient(top, #373a3d, #313437);
width:250px;
padding:30px;
border-radius:3px;
margin:20px 20px 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
I added code to reflect upload_files
#upload_files{
font-family:'PT Sans Narrow', sans-serif;
background-color:#373a3d;
background-image:-webkit-linear-gradient(top, #373a3d, #313437);
background-image:-moz-linear-gradient(top, #373a3d, #313437);
background-image:linear-gradient(top, #373a3d, #313437);
width:250px;
padding:30px;
border-radius:3px;
margin:20px 20px 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
Its not a "clean" solution, but it works :)
I was having this issue for a long time, until I figured I would fix it. Here's what I did.
In the form, I added classes to the #upload and #drop elements. I renamed them to #upload1, #upload2 and #drop1, #drop2
<form id="upload1" class="upload" method="post" action="upload.php" enctype="multipart/form-data">
<div id="drop1" class="drop">
...
On the JS side (script.js), I wrapped the whole thing in a proper jQuery init and I added a jQuery each at the top and wrapped the entire main area in this:
(function($){
$('.upload').each(function (_key, _value) {
var $this = $(this);
var ul = $this.find('ul');
$this.find('#drop a').click(function(){
...
});
})(jQuery);
I also replaced all instances of #upload with $this and all instances of #drop with $this.find('.drop')
Basically, you're replacing the ids with class names, and adjusting your script accordingly, and wrap it all in a big each loop.
PS. I also like to add a complete callback to my script file so I can do things after everything.
complete:function() {
},
Please let me know if this works for you.
UPDATE:
Modified the code to work dynamically:
(function($){
$(document).ready(function(){
$(document).on('click','.drop a', function(){
var $drop = $(this);
var $this = $drop.closest('.upload');
var ul = $this.find('ul');
$this.parent().find('input').click();
//console.log($this.find('.drop'));
});
window.init_file_upload = function($element) {
// Initialize the jQuery File Upload plugin
$($element).fileupload({
//var $this = $(this);
// This element will accept file drag/drop uploading
dropZone: $element.find('.drop'),
// This function is called when a file is added to the queue;
// either via the browse button, or via drag/drop:
add: function (e, data) {
ul = $element.find('ul');
//console.log('adsf');
$('.ajaxform button.submit').attr('disabled','disabled');
var tpl = $('<li class="working"><input type="text" value="0" data-width="48" data-height="48"'+
' data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" /><p></p><span><i class="fa fa-check-circle-o"></i> OK</span></li>');
// Append the file name and file size
tpl.find('p').text(data.files[0].name)
.append('<i>' + formatFileSize(data.files[0].size) + '</i>');
// Add the HTML to the UL element
ul[0].innerHTML = '';
data.context = tpl.appendTo(ul);
// Initialize the knob plugin
tpl.find('input').knob();
// Listen for clicks on the cancel icon
tpl.find('span').click(function(){
if(tpl.hasClass('working')){
jqXHR.abort();
}
tpl.fadeOut(function(){
tpl.remove();
});
});
// Automatically upload the file once it is added to the queue
var jqXHR = data.submit();
},
progress: function(e, data){
// Calculate the completion percentage of the upload
var progress = parseInt(data.loaded / data.total * 100, 10);
// Update the hidden input field and trigger a change
// so that the jQuery knob plugin knows to update the dial
data.context.find('input').val(progress).change();
if(progress == 100){
data.context.removeClass('working');
}
},
complete:function(e, data) {
// console.log(e,data);
var _data = $.parseJSON(e.responseText);
// console.log(_data);
postAjax(_data);
$('.ajaxform button.submit').removeAttr('disabled');
},
fail:function(e, data){
// Something has gone wrong!
data.context.addClass('error');
}
});
}
$('.upload').each(function() {
window.init_file_upload($(this));
});
// Simulate a click on the file input button
// to show the file browser dialog
// Prevent the default action when a file is dropped on the window
$(document).on('drop dragover', function (e) {
e.preventDefault();
});
// Helper function that formats the file sizes
function formatFileSize(bytes) {
if (typeof bytes !== 'number') {
return '';
}
if (bytes >= 1000000000) {
return (bytes / 1000000000).toFixed(2) + ' GB';
}
if (bytes >= 1000000) {
return (bytes / 1000000).toFixed(2) + ' MB';
}
return (bytes / 1000).toFixed(2) + ' KB';
}
});
})(jQuery);
Related
I'm wanting a checkbox in theme.php to trigger a function in front.php
that changes a css file from default with a white background to blue with a blue background.
Unchecking the checkbox reverts it back to default.
I've tried various different methods from having the script in theme.php to moving it to front.php using all the different jQuery functions including load, change, click, post, using if/else, appending to the header tags in front.php...
nothing works.
in theme.php
<div class="main-content">
<input type="checkbox" id="front"/>
<label for="front">FrontEnd</label>
</div>
and in front.php
const frontEnd = document.querySelector("#front");
frontEnd.addEventListener('change', function(e) {
if(frontEnd.checked){
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "css/blue.css";
document.getElementsByTagName("head")[0].appendChild(link);
}else{
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "css/default.css";
document.getElementsByTagName("head")[0].appendChild(link);
}
});
any tips on what I may be missing?
cheers.
$(document).ready(function($){
$('#test').click(function(){
$("#main-div").toggleClass('class-yellow');
});
// $('#test').prop('checked', true); //Checks it
// $('#test').prop('checked', false); //Unchecks it
});
.class-yellow {
background:yellow;
width:200px;
padding:10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='main-div'>
<label for="test">adding style when click</label>
<input type="checkbox" id='test'>
</div>
I have an HTML form like the one shown below, which after submitting is processed by PHP:
<form action="<?php print $_SERVER['PHP_SELF'] ?>" method="POST" enctype="multipart/form-data" id="decisions_form">
<!-- ... -->
<div style="text-align:center;">
<input type="submit" name="submit" value="Submit Decisions" id="decisions_button">
</div>
</form>
PHP does some processing, which could take a few seconds. After processing is complete, I refresh the page as below (probably not best practice, I don't know):
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// PHP...
}
echo ('<meta http-equiv="refresh" content="0.1;">');
?>
I would like to show a full-screen "loader/spinner", which would be activated after submitting and during PHP processing. Normally, If I understand it correctly, this loader/spinner should be interrupted by the refresh page command -- which is what I want
Looking for such loaders was unsuccessful, if not totally confusing for a inexperienced person like me.
It would be ideal if I could avoid JS and do it in a pure HTML/CSS fashion (is it even possible?).
I am not aware of a mechanism to do it in pure HTML. There are probably other and more sophisticated ways to do it than what I show below, but this worked well for me. Every time you place a call to the server, the ajax start function executes and delays 1 second (change the delay however you want) and then displays the waiting gif. When the ajaxStop function is called upon completion of the server call and stops the wait gif and enables the buttons. Note this should be the first tag in your html file after the css definitions.
Javascript code
<script defer>
$( document ).ready(function() {
// gif on 1 second timer delay before displaying, so user does not have it appear to quickly if the delay is short.
var loadingTimer;
$(document).ajaxStart(function() {
$(':button').prop('disabled', true); // disable all the buttons
loadingTimer = setTimeout("$('#process-wait').show()", 1000); // show the waiting gif
});
$(document).ajaxStop(function() {
clearTimeout(loadingTimer);
$("#process-wait").hide(); // hide the waiting gif
$(':button').prop('disabled', false); // enable all the buttons
});
});
</script>
Here is the css you need to go along with that. You can make it as big as you want, by adjusting the height and width values. Pick your own gif image simply set the url parameter to the directory path and name of the gif file.
#process-wait {
background: transparent url(images/process-wait.gif);
background-repeat: no-repeat;
height: 150px;
width: 150px;
z-index: 99999;
display:none;
position: absolute;
top: 50%;
left: 50%;
margin-left: 10px;
margin-top: 0px;
transform: translate(-50%, -50%);
Here's a complete example:
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
header("Content-Type: application/json");
echo json_encode($_SERVER);
exit;
}
?>
<!doctype html>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
<div hidden class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
<form action="<?php print $_SERVER['PHP_SELF'] ?>" method="POST" enctype="multipart/form-data" id="decisions_form">
<input type="text" name="dummy" value="dummy value">
<!-- ... -->
<div style="text-align:center;">
<input type="submit" name="submit" value="Submit Decisions" id="decisions_button">
</div>
</form>
<div class="complete" hidden>
Submission received<br>
<button class="reset">Reset</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
<script>
window.addEventListener('load', () => {
const decisionsForm = document.querySelector('#decisions_form');
const spinner = document.querySelector('.spinner-border');
const complete = document.querySelector('.complete');
const resetButton = document.querySelector('.reset');
// Show spinner, hide form
function formSending() {
spinner.removeAttribute('hidden');
decisionsForm.style.display = 'none';
}
// Hide spinner, show complete message
function formSent() {
complete.removeAttribute("hidden");
spinner.setAttribute("hidden", true);
}
// Show form, hide everything else
function reset() {
decisionsForm.style.display = 'block';
spinner.setAttribute("hidden", true);
complete.setAttribute("hidden", true);
}
// Send form data in the background
async function submitDecisionsForm(event) {
// Display spinner
formSending();
// Collect data to send
// event.target = the form
// event.target.action the action property on <form action="">
// the POST body gets set by reading the data from the form object (event.target)
const response = await fetch(event.target.action, {method: "POST", body: new FormData(event.target)});
// Submit is complete.. show the complete message and reset button
formSent();
// Format the response if you want to use it later
const responseJson = await response.json(); // or response.text() depending on what send back from the server
// Output to browser's dev console for debugging
console.log(text);
}
// Capture submit event
decisionsForm.addEventListener("submit", (event) => {
// Stop form from submitting immediately by default
event.preventDefault();
// Send form data in the background
submitDecisionsForm(event);
});
// demo: reset the form when clicking the reset button
resetButton.addEventListener('click', reset);
});
</script>
See comments in the code for explanation of parts.
My JQuery populates $_FILES only when click on input type file but not when drop in a file.
All the examples, tutorials, documentation I have found is about using Ajax or pure JavaScript. None is what I want to do. I have found also plently of plugins, libraries, ... I just want to be able to drop a file.....
The FORM:
<form id="item-form" role="form" method="post" enctype="multipart/form-data">
<div id="image-holder" class="dropBox">
<img src="" style="width: 100%; padding: 10px;display: none;">
</div>
<div id="fileBox">
<input type="file" name="image_file_input" id="image_file_input" />
</div>
<button type="submit" name="submit">SAVE</button>
</form>
The JQUERY:
$(".dropBox").on("drop", function(e) {
e.preventDefault();
e.stopPropagation();
runUpload( e.originalEvent.dataTransfer.files[0] );
});
$(".dropBox").click(function(){
$("#image_file_input").click();
});
$('input[type=file]').on('change', function(){
runUpload( this.files[0] );
});
function runUpload( file ) {
var reader = new FileReader(), image = new Image();
reader.readAsDataURL( file );
reader.onload = function( file ) {
var image_holder = $("#image-holder");
image_holder.empty();
$("<img />", {
"src": file.target.result,
"class": ""
}).appendTo(image_holder);
$("#dropBox").hide();
$(image_holder).show();
}
The PHP:
if ( !empty($_FILES) ) {
echo '---> Files not empty ';
}else{
echo '---> Files empty ';
}
I don't want to use Ajax. I'm only showing the relevant part of the code to concentrate in the issue.
If I click on the dropBox or I drop a file (image) into the dropBox element I can see the image selected in the image_holder div.
When the form is submited if the file is from a click event it works perfectly but when is from a drop event $_FILES is empty.
I'm convinced the problem is what I pass to the runUpload function when dropping. I have tried all sort of things but unable to see what is wrong.
I am using Fine Uploader (v5.0.1) with jQuery, jQuery.validate and jQuery.form plugins for a multi-field form for new events which can have zero to two file attachments.
I have it working, but I have a few questions before I go further.
My client-side code is generating one POST request for each file (including the other form elements) plus one additional POST request for only the other form elements. So, if my form has two file attachments, I am getting three POST requests. Is this normal behavior? Can I get everything in one POST request?
If multiple POST requests is normal behavior, I will have to generate some sort of unique identifier at the client prior to the first POST request, so I can avoid duplication of event records in my database and to associate each file upload with the correct event. If this is the direction I need to go, are there any examples of this type of implementation I can look at?
If no files are attached, I am getting an alert dialog: "No files to upload." The form can be submitted with no file attachments, so I don't want to imply to the user that he/she must attach files. How can I get rid of this dialog?
I am currently getting one POST response for the form data plus one POST response for each file uploaded. Is there a way to handle only the final POST response (e.g., form.onAllComplete)? What if the form has no file attachments?
I am using one server endpoint for the form, including file uploads. Should I be using two separate endpoints, one for the other form fields and one for file uploads?
Here is my form: http://www.paulrachal.com/test/fineuploader-test.htm
Here is my code:
Client:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<title>New Event</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.css" />
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.13.0/jquery.validate.min.js"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>
<!-- Fine Uploader -->
<link rel="stylesheet" href="../css/custom.fineuploader-5.0.1.min.css" />
<script src="../js/custom.fineuploader-5.0.1.min.js"></script>
<!-- document.ready -->
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
<!-- event handlers -->
// hide the file upload button when the page loads
$( '#manual-fine-uploader' ).hide();
// show the file upload button on change in attachments checkbox
$("#hasattachments").change(function() {
if ($('#hasattachments:checked').length) {
$('#manual-fine-uploader').show();
}
else {
$('#manual-fine-uploader').hide();
}
})
<!-- Fine Uploader setup -->
var manualuploader = $('#manual-fine-uploader').fineUploader({
request: {
endpoint: 'fineuploader-test.php'
},
form: {
element: 'new-event'
},
template: "qq-template-manual-noedit",
validation: {
allowedExtensions: ['txt', 'pdf'],
itemLimit: 2,
sizeLimit: 256000 // 250 kB = 250 * 1024 bytes
},
autoUpload: false
});
<!-- form validation -->
// setup form validation on the form element
$("#new-event").validate({
// validation rules
rules: {
description: {
required: {
depends: function(element) {
if ( $("input[name='eventtype']:checked").val() == "3" || $("input[name='eventtype']:checked").val() == "4" || $("input[name='eventtype']:checked").val() == "5" )
return true;
}
}
},
},
// validation error messages
messages: {
description: "Please enter a description"
},
// submit handler
submitHandler: function(form) {
$("#send").attr("value", "Sending...");
$(form).ajaxSubmit({
target: "#response",
dataType: "json",
success: function processJson(response) {
if (response.success)
{
$(form).slideUp("fast");
$("#response").html("<span class='success'>" + response.success + "</span>").hide().slideDown("fast");
} // end if
else if (response.failure)
{
$("#response").empty();
$(".error").removeClass("error");
$errors = response.failure;
for ($i = 0; $i < $errors.length; $i++) {
$error = $errors[$i];
$.each($error, function(key, value) {
// append error text to div#response
$("#response").append("<li class='failure'>" + value + "</li>").hide();
// set form elements based on the error
switch(key) {
case "description-isempty":
$("#description").addClass("error");
break;
case "eventname-isempty":
$("#eventname").addClass("error");
break;
case "eventtype-isinvalid":
$("#eventtype-input").addClass("error");
break;
default:
// default statements if no cases are true
} // end switch
}); // end $.each
} // end for
$("#response").addClass("failure");
$("#response").slideDown("fast");
$("html, body").animate({ scrollTop: 0 }, "fast");
} // end else if
} // end processJson
});
return false;
}
}); // end #new-event.validate
<!-- validate individual fields on change -->
// #description
$('#description').on('change', function() {
$('#new-event').validate().element('#description');
});
}); // end document.ready
</script>
<!-- Fine Uploader Template -->
<script type="text/template" id="qq-template-manual-noedit">
<div class="qq-uploader-selector qq-uploader">
<div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
<span>Drop files here to upload</span>
</div>
<div class="qq-upload-button-selector qq-upload-button">
<div>Browse...</div>
</div>
<span class="qq-drop-processing-selector qq-drop-processing">
<span>Processing dropped files...</span>
<span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
</span>
<ul class="qq-upload-list-selector qq-upload-list">
<li>
<div class="qq-progress-bar-container-selector">
<div class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
<span class="qq-upload-spinner-selector qq-upload-spinner"></span>
<span class="qq-upload-file-selector qq-upload-file"></span>
<span class="qq-upload-size-selector qq-upload-size"></span>
<a class="qq-upload-cancel-selector qq-upload-cancel" href="#">Cancel</a>
<span class="qq-upload-status-text-selector qq-upload-status-text"></span>
</li>
</ul>
</div>
</script>
<!-- styles -->
<style type="text/css">
.qq-upload-button-selector {
background: #0080FF;
}
#response {
margin-bottom: 20px;
text-align: center;
}
#response .success {
color: #08a300;
}
#response .failure {
color: #dc0000;
}
div.failure {
background-color: #FF0;
}
.error {
border: 2px solid red;
}
input.error {
border: 2px solid red;
}
select.error {
border: 2px solid red;
}
</style>
</head>
<body>
<!-- new-event-form -->
<div id="new-event-form" data-role="page">
<!-- header -->
<div data-role="header"><h1>NEW EVENT</h1></div>
<div class="content" data-role="content">
<div id="response"></div>
<form id="new-event" action="fineuploader-test.php" method="post">
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Event Type:</legend>
<div id="eventtype-input">
<input type="radio" name="eventtype" id="eventtype_1" value="1" checked="checked" />
<label for="eventtype_1">Ride</label>
<input type="radio" name="eventtype" id="eventtype_2" value="2" />
<label for="eventtype_2">Clinic</label>
<input type="radio" name="eventtype" id="eventtype_3" value="3" />
<label for="eventtype_3">Social Event</label>
<input type="radio" name="eventtype" id="eventtype_4" value="4" />
<label for="eventtype_4">Meeting</label>
<input type="radio" name="eventtype" id="eventtype_5" value="5" />
<label for="eventtype_5">Non-Club Event</label>
</div>
</fieldset>
</div>
<div data-role="fieldcontain">
<label for="eventname">Event Name:</label>
<input type="text" name="eventname" id="eventname" value="" maxlength="40" required />
</div>
<div id="descriptioninput" data-role="fieldcontain">
<label for="description">Description:</label>
<input type="text" name="description" id="description" value="" maxlength="40" />
</div>
<div id="attachments" data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Attachments:</legend>
<input type="checkbox" name="hasattachments" id="hasattachments" value="1" />
<label for="hasattachments">Attachments</label>
</fieldset>
</div>
<div id="manual-fine-uploader">Browse...</div>
<div class="ui-body ui-body-b">
<fieldset class="ui-grid-a">
<div class="ui-block-a"><input type="reset" data-theme="d" value="Cancel"></div>
<div class="ui-block-b"><input type="submit" data-theme="a" value="Submit"></div>
</fieldset>
</div>
</form>
</div> <!-- /content -->
</div> <!-- /page -->
</body>
</html>
Server:
<?php
// get values from POST request
$eventtype = $_POST['eventtype']; // eventtype field
$eventname = $_POST['eventname']; // eventname field
$description = $_POST['description']; // description field
$hasattachments = $_POST['hasattachments']; // hasattachments field
$qqfile = $_POST['qqfile']; // file upload field
$qquuid = $_POST['qquuid']; // file upload uuid
$qqfilename = $_POST['qqfilename']; // file upload filename
// include the upload handler class
require_once "handler.php";
// initialize errors array
$errors = array();
// validate elements
// eventtype
$eventtypes = array_flip(array('1', '2', '3', '4', '5'));
if (!isset($eventtypes[$eventtype])) $errors = addError("eventtype-isinvalid");
// eventname
$eventname = filter_var($eventname, FILTER_SANITIZE_STRING);
if(empty($eventname)) $errors = addError("eventname-isempty");
// description
$description = filter_var($description, FILTER_SANITIZE_STRING);
if (empty($description)) $errors = addError("description-isempty");
// file uploads
if ($hasattachments == 1) uploadFiles();
// functions
// add error
function addError($error) {
switch ($error)
{
case "description-isempty":
$errors[] = array("description-isempty" => "Please enter a description.");
break;
case "eventname-isempty":
$errors[] = array("eventname-isempty" => "Please enter an event name.");
break;
case "eventtype-isinvalid":
$errors[] = array("eventtype-isinvalid" => "Please select an event type.");
break;
} // end switch($error)
return $errors;
} // end function addError()
// file uploads
function uploadFiles() {
$uploader = new UploadHandler();
// specify the list of valid extensions
$uploader->allowedExtensions = array("txt", "pdf");
// specify max file size in bytes
$uploader->sizeLimit = 250 * 1024; // 250 kB
// specify the input name set in the javascript.
$uploader->inputName = "qqfile"; // matches Fine Uploader's default inputName value by default
// specify the folder to temporarily save parts to use the chunking/resume feature
$uploader->chunksFolder = "chunks";
$method = $_SERVER["REQUEST_METHOD"];
if ($method == "POST") {
header("Content-Type: text/plain");
// call handleUpload() with the name of the folder, relative to PHP's getcwd()
$result = $uploader->handleUpload("uploads/");
// get the name used for uploaded file
$result["uploadName"] = $uploader->getUploadName();
} // end if
} // end function uploadFiles()
// return response
if (!empty($errors)) $response = array("failure" => $errors);
else $response = array("success" => "Success! Your event has been posted.");
echo json_encode($response);
?>
Answering your questions in order:
Fine Uploader sends each file in a separate request, and there is no way to change this.
Fine Uploader already generates a unique ID (UUID) for each file. This ID is sent with the upload request. If you want to send additional data for a file, you can do so via the setParams API method. This will send additional, custom parameters of your choice along with the file. You can specify new params for all files, or a specific file.
In form mode, Fine Uploader intercepts the submit request and sends the file(s) and all form fields via ajax/XHR. Currently, it expects at least one file to be selected, as the form fields are sent as parameters for each selected file. A lack of selected files means that, in its current state, the form fields cannot be sent. Changing this will require adjustments to Fine Uploader's internal code. You can work around this by not utilizing form mode. Instead, you'll need to submit your form data in one request, and then have Fine Uploader send any selected files via the API.
Fine Uploader should intercept the form submit, so there should only be one response per file. The form fields are sent with each file.
This may be the required approach if you want to make the file field optional for your users.
I know I have no issues with installing uploadprogress extension because when I tried this very simple tutorial: http://www.ultramegatech.com/2010/10/create-an-upload-progress-bar-with-php-and-jquery/, it worked beautifully!
I then tweaked it just a little bit to have a very simple (not jQuery-UI) progress bar, which also worked. Here's the working code:
upload_getprogress.php:
<?php
if (isset($_GET['uid'])) {
$status = uploadprogress_get_info($_GET['uid']);
if ($status) {
echo round($status['bytes_uploaded']/$status['bytes_total']*100);
}
else {
echo 100;
}
}
?>
upload_form.php:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Upload Something</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<style>
#progress-bar, #upload-frame {
display: none;
}
</style>
<script>
(function ($) {
var pbar;
var started = false;
$(function () {
$('#upload-form').submit(function() {
$('#upload-form').hide();
pbar = $('#progress-bar');
pbar.show();
$('#upload-frame').load(function () {
started = true;
});
setTimeout(function () {
updateProgress($('#uid').val());
}, 1000);
});
});
function updateProgress(id) {
var time = new Date().getTime();
$.get('upload_getprogress.php', { uid: id, t: time }, function (data) {
var progress = parseInt(data, 10);
if (progress < 100 || !started) {
started = progress < 100;
updateProgress(id);
}
started && $('#inner').css('width', progress+ "%");
});
}
}(jQuery));
</script>
<style>
#progress-bar
{
height:50px;
width:500px;
border:2px solid black;
background-color:white;
margin:20px;
}
#inner
{
height:100%;
background-color:orange;
width:0%;
}
</style>
</head>
<body>
<form id="upload-form"
method="post"
action="upload.php"
enctype="multipart/form-data"
target="upload-frame" >
<input type="hidden"
id="uid"
name="UPLOAD_IDENTIFIER"
value="<?php echo $uid; ?>" >
<input type="file" name="file">
<input type="submit" name="submit" value="Upload!">
</form>
<div id="progress-bar"><div id='inner'></div>
<iframe id="upload-frame" name="upload-frame"></iframe>
</body>
</html>
All fine and dandy, no issues! So I know for a fact there is nothing wrong with the way I've set up the uploadprogress extension.
However, having completed the demo successfully, I needed to integrate it into my javascript and jQuery intensive web-app, which includes file uploads.
Now when I try it, I get “NULL” from the uploadprogress_get_info() function. Why?
In my application page, my image upload form is created dynamically. But at the beginning of my page (and before the user hits a button that dynamically creates an image upload form), I am using this line:
<input type='hidden' name='UPLOAD_IDENTIFIER' id='uid' value='<?php echo md5(uniqid(mt_rand())); ?>' />
Is this the problem? Is there a specific time or place this hidden input should be present?
Before including the above line at the top of my page, I've also included a long .js file that includes a bunch of jQuery plugins, but starts with the following code:
var started = false;
function updateProgress(id) {
console.log("updating progress"); // this msg appears, so i know i'm getting this far
var time = new Date().getTime();
$.get('upload_getprogress.php', { uid: id, t: time }, function (data) {
var progress = parseInt(data, 10);
if (progress < 100 || !started) {
started = progress < 100;
updateProgress(id);
}
//started && pbar.progressbar('value', progress);
$('#inner').css('width', progress+ "%");
});
}
// a lot more functions, then:
function imageDialog(imgtype, x, y, editsource) {
// this function dynamically generates a dialog for image uploading
// which shows up when a user hits an "image upload" button
// there's lots of code that creates a new form which is assigned to $imgform
// lots of elements and a couple of iframes are appended to $imgform
// then finally:
$imgform.submit(function() {
pbar = $('#progress-bar');
$('#inner').css('width', "0%");
pbar.show();
started = true;
setTimeout(function () {
updateProgress($('#uid').val());
}, 1000);
});
/* other irrelevant stuff */
}
However, while the upload progress bar shows up as expected, it never increases in progress.
So I edited the upload_getprogress.php to look like this:
if (isset($_GET['uid'])) {
$uid = $_GET['uid'];
//$status = uploadprogress_get_info($_GET['uid']);
echo "progress for $uid is: ".uploadprogress_get_info($uid);
}
In Firefox, I can see the response of the ajax call, and what I get as output from upload_getprogress.php is:
progress for 6e728b67bd526bceb077c02231d2ec6f is:
I tried to dump $status into a variable and output to file, and the file said:
the current uid: 02e9a3e0214ffd731265ec5b0b220b4c
the current status: NULL
So basically, the status is consistently returning NULL. Why? This was (and still is) working fine in the demo, what could be going wrong while integrating it into my web app code? There's nothing wrong with the image uploading on its own - my images are getting uploaded fine, but the progress isn't getting tracked!
The form that gets created dynamically looks like this:
<div class="dialog-container">
<form id="imgform" method="post" enctype="multipart/form-data" action="upload_1-img.php" target="upload_target">
Select image:
<br>
<input id="image" type="file" name="image">
<div id="imgwrapper"></div>
<input id="filename" type="hidden" value="" name="filename">
<input id="upath" type="hidden" value="xxxxxxxxxxxxxxxxxxxxxxxxxx" name="upath">
<center>
<input id="imgupload" type="submit" onclick="showUploadedItem()" value="Upload">
<input id="clearcrop" type="button" disabled="disabled/" value="Clear selection">
<input id="imgapproved" type="button" disabled="disabled" value="Done">
<input id="imgcancel" type="button" value="Cancel">
</center>
</form>
</div>
<div id="progress-bar"><div id='inner'></div></div>
<!-- etc etc some other elements -->
</div>
and my own upload_1-img.php starts off with:
$filename = $_FILES["image"]["tmp_name"];
$file_info = new finfo(FILEINFO_MIME);
$bfr = $file_info->buffer(file_get_contents($filename)) or die ("error");
// some more stuff, getting file type and file's $name
if( /* a bunch of conditions */ )
move_uploaded_file( $_FILES["image"]["tmp_name"], $upath . "/" . $name);
Woohoo! I figured it out, thanks to this bug:
https://bugs.php.net/bug.php?id=57505
Basically, just I removed this static line from the page where users get to upload files:
<input type='hidden' name='UPLOAD_IDENTIFIER' id='uid' value='<?php echo md5(uniqid(mt_rand())); ?>' />
and in my javascript function that creates the image dialog dynamically, I just added the hidden input dynamically, right above the line where I generated the file input.
So the relevant part of the dynamically created form then looks like:
<input type='hidden' name='UPLOAD_IDENTIFIER' id='uid' value='1325a38f3355c0b1b4' />
<input id="image" type="file" name="image">
Now since this is getting dynamically created via javascript anyway, I can just replace that value above with a random js function.
Now the progress bar is advancing as it ought to! :D