Failure of file upload

Hello,

I have two questions regarding failed uploads.

  1. Is there a way to display an error message for each failed upload?

In my experiments I return {state: true} for successful uploads and {state: fail} . I assume I can add more properties to the response, including a message explaining the reason for the failure. However, such a message will be ignored by your code and won’t be displayed to the user.
The reason we need this feature is that uploads may fail due to different reasons, such as illegal file type, too large file, exceeded quota, etc… It would be useful to display the reason to the user.

  1. How do you detect upload failures in flash mode ?

I tested the file upload in all three modes - html4, html5 & flash. In the first two, if the server returns a state other than true, the upload is marked as failed. However, in the flash mode failed uploads appear to be successful.
I tried to figure out the reason for this behavior by reading the source code of dhtmlxform_item_upload.js
For the html4 & html5 modes I found the code that checks the returned status to determine if the upload failed (and calls _onUploadFailed when necessary) :

HTML5 mode :

[code] _doUploadFile: function(id) {

	var that = this;
	
	if (!this._loader) {
		this._loader = new XMLHttpRequest();
		this._loader.upload.onprogress = function(e) {
			if (that._files[this._idd].state == "uploading") that._updateFileInList(this._idd, "uploading", Math.round(e.loaded*100/e.total));
		}
		this._loader.onload = function(e) {
			try {eval("var r="+this.responseText);} catch(e){};
			if (typeof(r) == "object" && typeof(r.state) != "undefined" && r.state == true) {
				that._onUploadSuccess(this._idd, r.name);
				r = null;
			} else {
				that._onUploadFail(this._idd);
			}
		}
		this._loader.onerror = function(e) {
			that._onUploadFail(this._idd);
		}
		this._loader.onabort = function(e) {
			that._onUploadAbort(this._idd);
		}
	}
	
	this._loader._idd = id;
	this._loader.upload._idd = id;
	
	var form = new FormData();
	form.append("file", this._files[id].file);
	this._loader.open("POST", this._url+(String(this._url).indexOf("?")<0?"?":"&")+"mode=html5&"+new Date().getTime(), true);
	this._loader.setRequestHeader("X-Requested-With", "XMLHttpRequest");
	this._loader.send(form);
	
}[/code]

HTML4 mode :

_onLoad: function() { if (this._uploading) { try {eval("var r="+this.fr.contentWindow.document.body.innerHTML);} catch(e){}; //this.fr.contentWindow.document.body.innerHTML = ""; if (typeof(r) == "object") { if (typeof(r.state) != "undefined") { if (r.state == "cancelled") { this._onUploadAbort(this.fr._idd); } else if (r.state == true) { if (typeof(r.size) != "undefined" && !isNaN(r.size)) this._files[this.fr._idd].size = r.size; this._onUploadSuccess(this.fr._idd, r.name); } r = null; return; } } this._onUploadFail(this.fr._idd); }

I couldn’t find similar code for the flash mode. Perhaps I was looking in the wrong place, but since the flash mode doesn’t seem to detect errors, I’m not sure about that.

Thanks,
Eran

Hi

Flash code in swf. You can use attachEvent(“onUploadFail”,f(){})
docs.dhtmlx.com/doku.php?id=dhtm … uploadfail

Hi Andrei,

Thanks for your answer.

However, it doesn’t explain why the flash mode didn’t detect the failed uploads. Does the Flash mode expect the same response (same as the html4 & html5 modes) from the server in order to determine if an upload succeeded or failed?
I used the same server code (a jsp file) for the Flash and html modes, and the server code was executed when I used the Flash mode, but the client reported all the uploads as successful, even though some of them failed in the server.

And as for using the onUploadFail event, the only parameter of this function is the name of the file that failed to upload. When my onUploadFail function is called, I have no way of getting the response that was returned from the server for that failed upload. Is there a way to access the server response form the event handler?

Thanks,
Eran

Try to change your response a bit, ‘state:fail’ not vaild json, add <"> around “fail” or use false, i.e.:
{state: ‘fail’, …}
or
{state: false, … }

also you can try in form init add:
{type: “upload”, swfLogs: “enabled”, …} ans check console output

Correct, there some code which ignore state:false in flash mode
also do the following:
dhtmlxform_item_uplaod.js, line about 347

[code]this._onUploadSuccess = function(id, serverName, r) {

if (typeof(t) != "undefined" && t.state == true && t.name != null) serverName = t.name;
// change with
if (typeof(t) != "undefined" && t.state == true && t.name != null) {
	serverName = t.name;
} else {
	this._onUploadFail(id);
	return;
}[/code]

and if you will return state:false from server, uploadFail will executed

  • } else {
    with
    } else if (this.engine == “flash”) {

Hi Andrei,

Thank you very much. Your suggestion worked!
Actually I changed it a little, because my server doesn’t return the name parameter on successful uploads.

if (typeof(t) != "undefined" && t.state == true) { if (t.name != null) { serverName = t.name; } } else if (this.engine == "flash") { this._onUploadFail(id); return; }

Is it something you fixed or going to fix on your next version?

And what about my other question?
If I return an additional error message field from the server (for failed uploads), can I access it from the onUploadFail event? Would that require changes in the code of dhtmlxform_item_uplaod.js ?

Thanks,
Eran

Hi Andrei,

I managed to change the code of dhtmlxform_item_upload.js to send an error message from the server to the onUploadFail event.
When I tested it on the three engines, I found a bug in the HTML4 engine - when the upload fails in the server, if the server returns a status (such as fail or false) the browser doesn’t detect the failure and seems to think the upload is still in progress.

I looked into the code and found the following :

[code] _onLoad: function() {
if (this._uploading) {
try {eval(“var r=”+this.fr.contentWindow.document.body.innerHTML);} catch(e){};
//this.fr.contentWindow.document.body.innerHTML = “”;
if (typeof® == “object”) {
if (typeof(r.state) != “undefined”) {
if (r.state == “cancelled”) {
this._onUploadAbort(this.fr._idd);
} else if (r.state == true) {
if (typeof(r.size) != “undefined” && !isNaN(r.size)) this._files[this.fr._idd].size = r.size;
this._onUploadSuccess(this.fr._idd, r.name);
}
r = null;
return;
}

		}
		this._onUploadFail(this.fr._idd);
	}
	
},[/code]

This code means that if the server returns a state other than true or cancelled (such as fail or false), the upload never ends as far as the client is concerned (since none of the methods _onUploadSuccess, _onUploadFail & _onUploadAbort are called).

Eran

Correct, change it a bit

if (typeof(r.state) != "undefined") { if (r.state == "cancelled") { this._onUploadAbort(this.fr._idd); r = null; return; } else if (r.state == true) { if (typeof(r.size) != "undefined" && !isNaN(r.size)) this._files[this.fr._idd].size = r.size; this._onUploadSuccess(this.fr._idd, r.name); r = null; return; } }

Regarding get state from server and pass it into user callback, probably this will added in future as additional param.

if you will change server response like:
{state: true, name:{info:“some server info”, state: “uploading state”, another_info: “some another info”}}

in your attached events you will have serverName value like this:
{info:“some server info”, state: “uploading state”, another_info: “some another info”}

just pass valid json
the only thing is myForm.send() will not stringify this value correctly.

uploadFail and other eventsw/o serverName param - you need to fix code