Jump to content

How can I upload large files with FormData by chunking the files using Web/Service Workers in jquery without any plugins


Recommended Posts

Posted

Hi, I'm developing a plugin which will allow users to upload files to the server as well as send form data to the server. But I need to chunk/slice large files using Web/Service Worker so that it doesn't break PHP's upload_max_filesize & post_max_size and don't halt the UI as well. But the problem is, if the form contains input fields, I need to send them as well. I want know how can I do that?

Posted

Okay, let me try this.

  • 2 weeks later...
Posted

Okay, I've tried but it's not working that way I've wanted.

Sorry but I don't have access to the Internet for the past 4 days, so I was not able to post the result here.

Here is the code of my plugin:

/****************************************************************************************************************************
******************************************************SGNUPLOAD v1.0.1*******************************************************
*****************************************************************************************************************************
*	DATE: October 15, 2018																									*
*	AUTHOR: Sagnik Ganguly																									*
*	E-MAIL: sagnikganguly2012@rediffmail.com																				*
*	WEBSITE: https://plugins.sgnetworks.cf/jquery/sgnupload																	*
*	DOCUMENTATION: https://docs.plugins.sgnetworks.cf/jquery/sgnupload														*
****************************************************************************************************************************/
if (!window.BlobBuilder) {
	window.BlobBuilder = window.WebKitBlobBuilder || window.MozBlobBuilder;
}

if (!window.URL) {
	window.URL = window.webkitURL || window.mozURL;
}
	
$.worker = function(args) { 
	var def = $.Deferred(function(dfd) {
		var worker;
		if (window.Worker) {
			var url = args.file;

			// If we have found a DOM object related,
			// we need constructo a `BlobBuilder` to
			// inline the web worker.
			if(args.id){
				var dom = document.querySelector('#' + args.id),
					blob = new BlobBuilder();

				blob.append(dom.textContent);
				url = window.URL.createObjectURL(blob.getBlob());
			}

			// Construct the Web Worker
			var worker = new Worker(url); 

			// If the Worker reports success, resolve the Deferred
			worker.onmessage = function(event) {			
				dfd.resolve(event); 
			};

			// If the Worker reports an error, reject the Deferred
			worker.onerror = function(event) {
				dfd.reject(event); 
			};

			// Create a pointer to 'postMessage' on the Deferred
			this.postMessage = function(msg){
				worker.postMessage(msg);
			};

			this.terminate = function(){
				worker.terminate();
			};

			// If args were passed, start the worker with supplied args
			if(args.args){
				worker.postMessage(args.args); 
			}
		} else {
			$.error("Worker is not supported in this browser!");
		}
	});

	return def; 
};
(function ($) {
	var SGNUpload = function (element, options) {
		var _pluginName = "SGNUpload",
		_version = "1.0.1";

		var SPACE_KB = 1024,
		SPACE_MB = 1024 * SPACE_KB;
		SPACE_GB = 1024 * SPACE_MB;
		SPACE_TB = 1024 * SPACE_GB;

		var _defaults = {
			onProgressUpdate: function (progress, loaded, lengthOfFile) {},
			onTaskCompleted: function (e, response) {},
			onTaskCancelled: function () {},
			onTaskFailed: function (e, error) {}
		}
		var _options = {
			url: '',
			formData: '',
			onProgressUpdate: '',
			onTaskCompleted: '',
			onTaskCancelled: '',
			onTaskFailed: ''
		}
		var plugin = this,
		$element = $(element);
		plugin.settings = {}

		function readBlob(opt_startByte, opt_stopByte) {

			var files = document.getElementById('files').files;
			if (!files.length) {
				alert('Please select a file!');
				return;
			}

			var file = files[0];
			var start = parseInt(opt_startByte) || 0;
			var stop = parseInt(opt_stopByte) || file.size - 1;

			var reader = new FileReader();

			// If we use onloadend, we need to check the readyState.
			reader.onloadend = function (evt) {
				if (evt.target.readyState == FileReader.DONE) { // DONE == 2
					/* document.getElementById('byte_content').textContent = evt.target.result;
					document.getElementById('byte_range').textContent =
					['Read bytes: ', start + 1, ' - ', stop + 1,
					' of ', file.size, ' byte file'].join(''); */
				}
			};

			var blob = file.slice(start, stop + 1);
			reader.readAsBinaryString(blob);
		}

		function Bytes2String(sizeInBytes) {
			if (sizeInBytes < SPACE_KB) {
				return sizeInBytes.toString() + " Byte(s)";
			} else if (sizeInBytes < SPACE_MB) {
				return (sizeInBytes / SPACE_KB).toString() + " KB";
			} else if (sizeInBytes < SPACE_GB) {
				return (sizeInBytes / SPACE_MB).toString() + " MB";
			} else if (sizeInBytes < SPACE_TB) {
				return (sizeInBytes / SPACE_GB).toString() + " GB";
			} else {
				return (sizeInBytes / SPACE_TB).toString() + " TB";
			}
		}
		function Bytes2ProgressString(progressInBytes, totalInBytes) {
			if (totalInBytes < SPACE_KB) {
				return progressInBytes.toString() + "/" + totalInBytes.toString() + " Byte(s)";
			} else if (totalInBytes < SPACE_MB) {
				return (progressInBytes / SPACE_KB).toString() + "/" + (totalInBytes / SPACE_KB).toString() + " KB";
			} else if (totalInBytes < SPACE_GB) {
				return (progressInBytes / SPACE_MB).toString() + "/" + (totalInBytes / SPACE_MB).toString() + " MB";
			} else if (totalInBytes < SPACE_TB) {
				return (progressInBytes / SPACE_GB).toString() + "/" + (totalInBytes / SPACE_GB).toString() + " GB";
			} else {
				return (progressInBytes / SPACE_TB).toString() + "/" + (totalInBytes / SPACE_TB).toString() + " TB";
			}
		}
		function percentage(progress, total) {
			return Math.round(total ? progress * 100 / total : 100);
		}
		function publishProgress(e,loaded,total) {
			var t = $.type(e),
			percent = t == "object" && e.lengthComputable ? percentage(e.loaded, e.total) + "%" :
				t == "number" ? e + "%" :
				t == "string" ? e :
				"0%";
			if(t=="object" && e.lengthComputable && loaded===undefine && total===undefined)
				plugin.settings.onProgressUpdate(percent, e.loaded, e.total);
			else if(t=="number" && $.isNumeric(loaded) && $.isNumeric(total))
				plugin.settings.onProgressUpdate(percent, loaded, total);
		}
		function werror(e) {
			console.log(e, 'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message);
		}
		function _create() {
			/* $.ajax({
			url: plugin.settings.url,
			type: 'POST',
			data: plugin.settings.formData,
			cache: false,
			contentType: false,
			processData: false,
			xhr: function(){
			var myXhr = $.ajaxSettings.xhr();
			if(myXhr.upload){
			myXhr.upload.addEventListener('progress', function(e){
			if(e.lengthComputable){
			publishProgress(e);
			}
			}, false);
			myXhr.upload.addEventListener('loadend', function(e){
			publishProgress(e);
			}, false);
			}
			return myXhr;
			},
			success: function(d){
			plugin.settings.onTaskCompleted(d);
			},
			error: function(xhr){
			plugin.settings.onTaskFailed(xhr);
			}
			}); */
			/******* HERE IS THE PROBLEM *******
			*AS MY PLUGIN IS ASSOCIATED ON $ INSTEAD OF $.fn, I DON'T HAVE ACCESS TO DOM ("#fileupload") AS USERS CAN HAVE AN ID OTHER THAN THAT*********
			* SO I NEED A WAY TO SUPPORT CHUNKED FILE UPLOADS WITH $.fn, I NEED A $. OBJECT */
			$("#fileupload").fileupload({
				url: plugin.settings.url,
				//dataType: 'json',
				done: function (e, data) {
					/* $.each(data.result.files, function (index, file) {
						$('<p/>').text(file.name).appendTo('#files');
					}); */
					plugin.settings.onTaskCompleted(e,data);
				},
				progress: function (e, data) {
					var progress = parseInt(data.loaded / data.total * 100, 10);
					/* $('#progress .progress-bar').css(
						'width',
						progress + '%'
					); */
					publishProgress(progress, data.loaded, data.total);
				},
				fail: function(e, data){
					plugin.settings.onTaskFailed(e,data);
				}
			})
		}

		plugin.init = function (args) {
			plugin.settings = $.extend(_defaults, args);
			$.each(plugin.settings, function (k, v) {
				if (typeof v === 'function') {
					if (_options.hasOwnProperty(k)) {
						_checked = true;
					} else {
						_checked = false;
						$.error('Invalid callback for: ' + k + ' in jQuery.' + _pluginName);
					}
				} else if (typeof v === 'string') {
					if ($.inArray(v, _options[k]) !== -1 || _options.hasOwnProperty(k)) {
						_checked = true;
					} else {
						_checked = false;
						$.error('Invalid value: ' + v + ' for option: ' + k + ' in jQuery.' + _pluginName);
					}
				}
			});
			if (_checked) {
				$element.data('options', plugin.settings);
				_create();
			} else {
				$.error('Something went wrong in jQuery.' + _pluginName);
			}
		}
	}
	$.SGNUpload = function (options) {
		var _this = this;
		var _plugin = new SGNUpload(this, options);
		_this.initialize = function (options) {
			_plugin.init(options);
			return this;
		}
		if (typeof options !== 'undefined')
			return this.initialize(options);
		return this;
	}
	return this;
})(jQuery);
And here is the inilization code of the plugin:

submitBtn.click(function(e){
		e.preventDefault();
		var $this=$(this);
		$(this).SGNSpinner({
			showContents: false,
			halign: 'center',
			valign: 'middle'
		});
		if(validationPassed){
			if(tos.prop("checked") && privacy.prop("checked")){
				var data=new FormData($('#sge-upload_gamePlayForm')[0]);
				$.each(files, function(key, value){
					data.append(key, value);
				});
				$.SGNUpload({
					url: '<?=$public_root;?>upload/ajax/gameplay',
					formData: data,
					onProgressUpdate: function(progress, loaded, lengthOfFile){
						console.log(progress, loaded, lengthOfFile);
					},
					onTaskCompleted: function(response){
						console.log(response);
					},
					onTaskCancelled: function(){
						
					},
					onTaskFailed: function(error){
						console.log(error);
					}
				});
			} else {
				$(this).SGNSpinner().hide();
				$this.SGNIMsg("You must be agree to our Terms Of Service & Privacy Policy in order to submit the form. Please read the agreements first then on the I agree buttons then submit the form again.");
			}
		} else {
			$(this).SGNSpinner().hide();
			alert("Please check the details and try again");
		}
	})
});

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...