XMLHttpRequest -> action = 500 Int Server Error

Hi all,

We’re trying to implement http://tutorialzine.com/2011/09/html5-file-upload-jquery-php/ into Yii. It all works fine when the XMLHttpRequest calls a .php file outside the protected folder. However, when I pasted the PHP into an action, Chrome Dev Tools says there is a 500 int server error. When previewing the request URL I could see a dummy echo I put in the action, hence the action actually gets called but probably refuses the request?

Any idea what the problem could be? Does XMLHttpRequest always need to request a file with a .php extension (action doesn’t have an extension)?

Thanks for your help,

Michael

JS in view:





// jquery file drop


(function($){


	jQuery.event.props.push("dataTransfer");

	var opts = {},

		default_opts = {

			url: '',

			refresh: 1000,

			paramname: 'userfile',

			maxfiles: 25,

			maxfilesize: 1, // MBs

			data: {},

			drop: empty,

			dragEnter: empty,

			dragOver: empty,

			dragLeave: empty,

			docEnter: empty,

			docOver: empty,

			docLeave: empty,

			beforeEach: empty,

			afterAll: empty,

			rename: empty,

			error: function(err, file, i){alert(err);},

			uploadStarted: empty,

			uploadFinished: empty,

			progressUpdated: empty,

			speedUpdated: empty

		},

		errors = ["BrowserNotSupported", "TooManyFiles", "FileTooLarge"],

		doc_leave_timer,

		stop_loop = false,

		files_count = 0,

		files;


	$.fn.filedrop = function(options) {

		opts = $.extend( {}, default_opts, options );

		

		this.bind('drop', drop).bind('dragenter', dragEnter).bind('dragover', dragOver).bind('dragleave', dragLeave);

		$(document).bind('drop', docDrop).bind('dragenter', docEnter).bind('dragover', docOver).bind('dragleave', docLeave);

	};

     

	function drop(e) {

		opts.drop(e);

		files = e.dataTransfer.files;

		if (files === null || files === undefined) {

			opts.error(errors[0]);

			return false;

		}

		

		files_count = files.length;

		upload();

		e.preventDefault();

		return false;

	}

	

	function getBuilder(filename, filedata, boundary) {

		var dashdash = '--',

			crlf = '\r\n',

			builder = '';


		$.each(opts.data, function(i, val) {

	    	if (typeof val === 'function') val = val();

			builder += dashdash;

			builder += boundary;

			builder += crlf;

			builder += 'Content-Disposition: form-data; name="'+i+'"';

			builder += crlf;

			builder += crlf;

			builder += val;

			builder += crlf;

		});

		

		builder += dashdash;

		builder += boundary;

		builder += crlf;

		builder += 'Content-Disposition: form-data; name="'+opts.paramname+'"';

		builder += '; filename="' + filename + '"';

		builder += crlf;

		

		builder += 'Content-Type: application/octet-stream';

		builder += crlf;

		builder += crlf; 

		

		builder += filedata;

		builder += crlf;

        

		builder += dashdash;

		builder += boundary;

		builder += dashdash;

		builder += crlf;

		return builder;

	}


	function progress(e) {

		if (e.lengthComputable) {

			var percentage = Math.round((e.loaded * 100) / e.total);

			if (this.currentProgress != percentage) {

				

				this.currentProgress = percentage;

				opts.progressUpdated(this.index, this.file, this.currentProgress);

				

				var elapsed = new Date().getTime();

				var diffTime = elapsed - this.currentStart;

				if (diffTime >= opts.refresh) {

					var diffData = e.loaded - this.startData;

					var speed = diffData / diffTime; // KB per second

					opts.speedUpdated(this.index, this.file, speed);

					this.startData = e.loaded;

					this.currentStart = elapsed;

				}

			}

		}

	}

    

    

    

	function upload() {

		stop_loop = false;

		if (!files) {

			opts.error(errors[0]);

			return false;

		}

		var filesDone = 0,

			filesRejected = 0;

		

		if (files_count > opts.maxfiles) {

		    opts.error(errors[1]);

		    return false;

		}


		for (var i=0; i<files_count; i++) {

			if (stop_loop) return false;

			try {

				if (beforeEach(files[i]) != false) {

					if (i === files_count) return;

					var reader = new FileReader(),

						max_file_size = 1048576 * opts.maxfilesize;

						

					reader.index = i;

					if (files[i].size > max_file_size) {

						opts.error(errors[2], files[i], i);

						filesRejected++;

						continue;

					}

					

					reader.onloadend = send;

					reader.readAsBinaryString(files[i]);

				} else {

					filesRejected++;

				}

			} catch(err) {

				opts.error(errors[0]);

				return false;

			}

		}

	    

		function send(e) {

			// Sometimes the index is not attached to the

			// event object. Find it by size. Hack for sure.

			if (e.target.index == undefined) {

				e.target.index = getIndexBySize(e.total);

			}

			

			var xhr = new XMLHttpRequest(),

				upload = xhr.upload,

				file = files[e.target.index],

				index = e.target.index,

				start_time = new Date().getTime(),

				boundary = '------multipartformboundary' + (new Date).getTime(),

				builder;

				

			newName = rename(file.name);

			if (typeof newName === "string") {

				builder = getBuilder(newName, e.target.result, boundary);

			} else {

				builder = getBuilder(file.name, e.target.result, boundary);

			}

			

			upload.index = index;

			upload.file = file;

			upload.downloadStartTime = start_time;

			upload.currentStart = start_time;

			upload.currentProgress = 0;

			upload.startData = 0;

			upload.addEventListener("progress", progress, false);

			

			xhr.open("POST", opts.url, true);

			xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' 

			    + boundary);

			    

			xhr.sendAsBinary(builder);  

			

			opts.uploadStarted(index, file, files_count);  

			

			xhr.onload = function() { 

			    if (xhr.responseText) {

				var now = new Date().getTime(),

				    timeDiff = now - start_time,

				    result = opts.uploadFinished(index, file, jQuery.parseJSON(xhr.responseText), timeDiff);

					filesDone++;

					if (filesDone == files_count - filesRejected) {

						afterAll();

					}

			    if (result === false) stop_loop = true;

			    }

			};

		}

	}

    

	function getIndexBySize(size) {

		for (var i=0; i < files_count; i++) {

			if (files[i].size == size) {

				return i;

			}

		}

		

		return undefined;

	}

    

	function rename(name) {

		return opts.rename(name);

	}

	

	function beforeEach(file) {

		return opts.beforeEach(file);

	}

	

	function afterAll() {

		return opts.afterAll();

	}

	

	function dragEnter(e) {

		clearTimeout(doc_leave_timer);

		e.preventDefault();

		opts.dragEnter(e);

	}

	

	function dragOver(e) {

		clearTimeout(doc_leave_timer);

		e.preventDefault();

		opts.docOver(e);

		opts.dragOver(e);

	}

	 

	function dragLeave(e) {

		clearTimeout(doc_leave_timer);

		opts.dragLeave(e);

		e.stopPropagation();

	}

	 

	function docDrop(e) {

		e.preventDefault();

		opts.docLeave(e);

		return false;

	}

	 

	function docEnter(e) {

		clearTimeout(doc_leave_timer);

		e.preventDefault();

		opts.docEnter(e);

		return false;

	}

	 

	function docOver(e) {

		clearTimeout(doc_leave_timer);

		e.preventDefault();

		opts.docOver(e);

		return false;

	}

	 

	function docLeave(e) {

		doc_leave_timer = setTimeout(function(){

			opts.docLeave(e);

		}, 200);

	}

	 

	function empty(){}

	

	try {

		if (XMLHttpRequest.prototype.sendAsBinary) return;

		XMLHttpRequest.prototype.sendAsBinary = function(datastr) {

		    function byteValue(x) {

		        return x.charCodeAt(0) & 0xff;

		    }

		    var ords = Array.prototype.map.call(datastr, byteValue);

		    var ui8a = new Uint8Array(ords);

		    this.send(ui8a.buffer);

		}

	} catch(e) {}

     

})(jQuery);





// html 5 file uploader script


$(function(){

	

	var dropbox = $('#dropbox'),

		message = $('.message', dropbox);

	

	dropbox.filedrop({

		// The name of the $_FILES entry:

		paramname:'pic',

		

		maxfiles: 5,

    	maxfilesize: 100,

		// THIS IS THE ACTION

		url: 'uploadProcess',

		

		uploadFinished:function(i,file,response){

			$.data(file).addClass('done');

			// response is the JSON object that post_file.php returns

		},

		

    	error: function(err, file) {

			switch(err) {

				case 'BrowserNotSupported':

					showMessage('Your browser does not support HTML5 file uploads!');

					break;

				case 'TooManyFiles':

					alert('Too many files! Please select 5 at most!');

					break;

				case 'FileTooLarge':

					alert(file.name+' is too large! Please upload files up to 100mb.');

					break;

				default:

					break;

			}

		},

		

		/* Called before each upload is started

		beforeEach: function(file){

			if(!file.type.match(/^image\//)){

				alert('Only images are allowed!');

				

				// Returning false will cause the

				// file to be rejected

				return false;

			}

		},*/

		

		uploadStarted:function(i, file, len){

			createImage(file);

		},

		

		progressUpdated: function(i, file, progress) {

			$.data(file).find('.progress').width(progress);

		}

    	 

	});

	

	var template = '<div class="preview">'+

						'<span class="imageHolder">'+

							'<img />'+

							'<span class="uploaded"></span>'+

						'</span>'+

						'<div class="progressHolder">'+

							'<div class="progress"></div>'+

						'</div>'+

					'</div>'; 

	

	

	function createImage(file){


		var preview = $(template), 

			image = $('img', preview);

			

		var reader = new FileReader();

		

		image.width = 100;

		image.height = 100;

		

		reader.onload = function(e){

			

			// e.target.result holds the DataURL which

			// can be used as a source of the image:

			

			image.attr('src',e.target.result);

		};

		

		// Reading the file as a DataURL. When finished,

		// this will trigger the onload function above:

		reader.readAsDataURL(file);

		

		message.hide();

		preview.appendTo(dropbox);

		

		// Associating a preview container

		// with the file, using jQuery's $.data():

		

		$.data(file,preview);

	}


	function showMessage(msg){

		message.html(msg);

	}


});


</script>



action in same controller as view




public function actionUploadProcess()

	{


echo "test";


		// If you want to ignore the uploaded files, 

		// set $demo_mode to true;

		

		$demo_mode = false;

		$upload_dir = '../../uploads/';

		$allowed_ext = array('jpg','jpeg','png','gif','docx','doc','notebook');

		

		

		if(strtolower($_SERVER['REQUEST_METHOD']) != 'post'){

			exit_status('Error! Wrong HTTP method!');

		}

		

		

		if(array_key_exists('pic',$_FILES) && $_FILES['pic']['error'] == 0 ){

			

			$pic = $_FILES['pic'];

		

			if(!in_array(get_extension($pic['name']),$allowed_ext)){

				exit_status('Only '.implode(',',$allowed_ext).' files are allowed!');

			}	

		

			if($demo_mode){

				

				// File uploads are ignored. We only log them.

				

				$line = implode('		', array( date('r'), $_SERVER['REMOTE_ADDR'], $pic['size'], $pic['name']));

				file_put_contents('/test/log.txt', $line.PHP_EOL, FILE_APPEND);

				

				exit_status('Uploads are ignored in demo mode.');

			}

			

			

			// Move the uploaded file from the temporary 

			// directory to the uploads folder:

			

			if(move_uploaded_file($pic['tmp_name'], $upload_dir.$pic['name'])){

				exit_status('File was uploaded successfuly!');

			}

			

		}

		

		exit_status('Something went wrong with your upload!');

		

		

		// Helper functions

		

		function exit_status($str){

			echo json_encode(array('status'=>$str));

			exit;

		}

		

		function get_extension($file_name){

			$ext = explode('.', $file_name);

			$ext = array_pop($ext);

			return strtolower($ext);

		}




	}