After much troubleshooting and debugging of this issue, I’ve found what I believe to be the cause, and a better workaround/solution. It’s a bit “hacky” (I’m an amateur dev!), so I’m open to any suggestions to improve this, though it does seem to work for me.
The files uploaded from the client are actually uploaded to this temp location on the server:
/tmp/systemd-private-random-number-httpd.service-random-number/tmp/sess_php-session-ID
Once the uploads have completed on the client side, the UI progress bar reaches 100% and remains so whilst the server is processing the files.
The processing on the server side involves moving (copying, then deleting) the file from the above /tmp location to the relevant blueimp location. (Assuming “user_dirs” is enabled/true in the blueimp options, the default destination is: /var/www/html/server/php/files/php-session-id/ ).
This copying process can take a significant amount of time, particularly on files larger than 2gb or thereabouts. Once the server processing has completed, blueimp triggers the “fileuploaddone” callback, and the UI updates to a completed state.
My aim was to provide some interactive UI feedback at this point (rather than hanging at 90% like the other workaround). My environment is capable of very large uploads (10gb+), so I didn’t find it acceptable not to provide any user feedback for what could be several minutes of file processing (with the user thinking the site has crashed, and closing the browser etc.).
My Workaround:
The first problem I encountered was that there doesn’t appear to be a blueimp callback for the point when the file uploads have completed on the client side, and the server processing begins. So I worked around this by creating a function (in main.js) to display my custom “processing div” after data.loaded matches data.total:
$('#fileupload').bind('fileuploadprogressall', function (e, data) { console.log(data);
if (data.loaded == data.total) {
setTimeout(function(){
$("#processwarn").fadeTo(300, 1);
},3000);
}})
My custom div that sits below the progress bar info is another php page that’s refreshed (with ajax.load) every couple of seconds and calculates the total file size of all the files in the current session upload folder (the directory total size didn’t seem to provide accurate results):
// Calculate size of files being processed
$filePath = "/var/www/html/server/php/files/*php-session-id*/";
$total = 0;
$d = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($filePath),
RecursiveIteratorIterator::SELF_FIRST
);
foreach($d as $file){
$total += $file->getSize();
}
// Convert to readable format
if ($total >= 1073741824)
{
$total = number_format($total / 1073741824, 2) . ' GB';
}
elseif ($total >= 1048576)
{
$total = number_format($total / 1048576, 2) . ' MB';
}
elseif ($total >= 1024)
{
$total = number_format($total / 1024, 2) . ' KB';
}
elseif ($total > 1)
{
$total = $total . ' bytes';
}
elseif ($total == 1)
{
$total = $total . ' byte';
}
else
{
$total = '0 bytes';
}
// Display spinner gif and size of file currently being processed
echo "<img src=\"img/spinner.gif\" height=\"20px\" width=\"20px\"> Please wait, processing files: $total";
The result looks something like this:

Edit: (after some more work) - With bootstrap progress bar added instead:

Additional point noticed from testing:
With chunking enabled (for example set to 1gb (maxChunkSize: 1000000000) ), the problem almost disappears, as the processing time appears drastically reduced to the user, as the "copying" processing occurs at the point of chunking (every 1gb in this example).
When the final processing then occurs, the server only has to "rechunk"/copy the last remaining 1gb over.
I also experienced quicker overall upload times due to this.
In hindsight, this may well be an easier/more effective solution for many.