From 13b14dc7f588973efbc5dba5e916e8a353ffb8a0 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Sat, 17 Dec 2016 21:37:30 +0900 Subject: [PATCH] Improve debugging and error handling for chunked file uploads --- .../js/plugins/jquery.fileupload/js/main.js | 77 +++++++++++++++---- modules/editor/editor.model.php | 11 ++- modules/file/file.controller.php | 35 +++++++-- modules/file/lang/en.php | 1 + modules/file/lang/ko.php | 1 + 5 files changed, 103 insertions(+), 22 deletions(-) diff --git a/common/js/plugins/jquery.fileupload/js/main.js b/common/js/plugins/jquery.fileupload/js/main.js index 8105596d8..1939ea164 100644 --- a/common/js/plugins/jquery.fileupload/js/main.js +++ b/common/js/plugins/jquery.fileupload/js/main.js @@ -62,21 +62,24 @@ var currentEnforce_ssl = window.enforce_ssl; if(location.protocol == 'https:') { window.enforce_ssl = true; } + + var chunkStatus = true; + var defaultFormData = { + "editor_sequence": data.editorSequence, + "upload_target_srl" : data.uploadTargetSrl, + "mid" : window.current_mid, + "act": 'procFileUpload' + }; var settings = { url: request_uri, - formData: { - "editor_sequence": data.editorSequence, - "upload_target_srl" : data.uploadTargetSrl, - "mid" : window.current_mid, - "act": 'procFileUpload' - }, + formData: defaultFormData, dropZone: $container, add: function(e, d) { var dfd = jQuery.Deferred(); $.each(d.files, function(index, file) { - if(data.settings.maxFileSize <= file.size) { + if(data.settings.maxFileSize > 0 && data.settings.maxFileSize < file.size) { dfd.reject(); alert(window.xe.msg_exceeds_limit_size); return false; @@ -88,15 +91,51 @@ d.submit(); }); }, + submit: function(e, data) { + data.formData = defaultFormData; + data.formData.nonce = "T" + new Date().getTime() + "." + Math.random(); + chunkStatus = true; + }, + chunksend: function(e, data) { + if (!chunkStatus) { + return false; + } + }, + chunkdone: function(e, res) { + if (res.result) { + if (res.result.error != 0) { + if (res.result.message) { + alert(res.result.message); + } else { + alert(window.xe.msg_file_upload_error + " (Type 1)"); + } + return chunkStatus = false; + } + } else { + alert(window.xe.msg_file_upload_error + " (Type 2)"); + return chunkStatus = false; + } + }, + chunkfail: function(e, data) { + if (chunkStatus) { + alert(window.xe.msg_file_upload_error + " (Type 3)" + "\n" + data.errorThrown + "\n" + data.textStatus); + return chunkStatus = false; + } + }, done: function(e, res) { var result = res.response().result; var temp_code = ''; - - if(!result) return; - - if(!jQuery.isPlainObject(result)) result = jQuery.parseJSON(result); - - if(!result) return; + if (!result) { + alert(window.xe.msg_file_upload_error + " (Type 4)"); + return false; + } + if (!jQuery.isPlainObject(result)) { + result = jQuery.parseJSON(result); + } + if (!result) { + alert(window.xe.msg_file_upload_error + " (Type 5)"); + return false; + } if(result.error == 0) { if(/\.(jpe?g|png|gif)$/i.test(result.source_filename)) { @@ -105,8 +144,18 @@ } _getCkeInstance(settings.formData.editor_sequence).insertHtml(temp_code, "unfiltered_html"); - } else { + } else if (result.message) { alert(result.message); + return false; + } else { + alert(window.xe.msg_file_upload_error + " (Type 6)"); + return false; + } + }, + fail: function(e, data) { + if (chunkStatus) { + alert(window.xe.msg_file_upload_error + " (Type 7)" + "\n" + data.errorThrown + "\n" + data.textStatus); + return false; } }, stop: function() { diff --git a/modules/editor/editor.model.php b/modules/editor/editor.model.php index 84f5b87c5..8f35c773a 100644 --- a/modules/editor/editor.model.php +++ b/modules/editor/editor.model.php @@ -305,8 +305,15 @@ class editorModel extends editor $file_config = $oFileModel->getUploadConfig(); $file_config->allowed_attach_size = $file_config->allowed_attach_size*1024*1024; $file_config->allowed_filesize = $file_config->allowed_filesize*1024*1024; - $file_config->allowed_chunk_size = min(FileHandler::returnBytes(ini_get('upload_max_filesize')), FileHandler::returnBytes(ini_get('post_max_size')) * 0.95, 100 * 1024 * 1024); - $file_config->allowed_chunk_size = floor($file_config->allowed_chunk_size / 131072) * 131072; + $file_config->allowed_chunk_size = min(FileHandler::returnBytes(ini_get('upload_max_filesize')), FileHandler::returnBytes(ini_get('post_max_size')) * 0.95, 64 * 1024 * 1024); + if ($file_config->allowed_chunk_size > 4 * 1048576) + { + $file_config->allowed_chunk_size = floor($file_config->allowed_chunk_size / 1048576) * 1048576; + } + else + { + $file_config->allowed_chunk_size = floor($file_config->allowed_chunk_size / 65536) * 65536; + } Context::set('file_config',$file_config); // Configure upload status such as file size diff --git a/modules/file/file.controller.php b/modules/file/file.controller.php index bd2be70a9..3f5be2051 100644 --- a/modules/file/file.controller.php +++ b/modules/file/file.controller.php @@ -67,7 +67,8 @@ class fileController extends file } // Check existing chunks - $temp_key = hash_hmac('sha1', sprintf('%d:%d:%d:%s', $editor_sequence, $upload_target_srl, $module_srl, $file_info['name']), config('crypto.authentication_key')); + $nonce = Context::get('nonce'); + $temp_key = hash_hmac('sha1', sprintf('%d:%d:%d:%s:%s', $editor_sequence, $upload_target_srl, $module_srl, $file_info['name'], $nonce), config('crypto.authentication_key')); $temp_filename = RX_BASEDIR . 'files/attach/chunks/' . $temp_key; if ($chunk_start == 0 && Rhymix\Framework\Storage::isFile($temp_filename)) { @@ -79,6 +80,11 @@ class fileController extends file Rhymix\Framework\Storage::delete($temp_filename); return new Object(-1, 'msg_upload_invalid_chunk'); } + if ($chunk_start >= 2 * 1024 * 1024) + { + Rhymix\Framework\Storage::delete($temp_filename); + return new Object(-1, 'msg_upload_invalid_chunk'); + } // Check size limit $is_admin = (Context::get('logged_info')->is_admin === 'Y'); @@ -116,7 +122,7 @@ class fileController extends file else { Rhymix\Framework\Storage::delete($temp_filename); - return new Object(-1, 'msg_upload_chunk_append_failed'); + return new Object(-1, 'msg_upload_invalid_chunk'); } } @@ -829,23 +835,40 @@ class fileController extends file } // Move the file - if($manual_insert || starts_with(RX_BASEDIR . 'files/attach/chunks/', $file_info['tmp_name'])) + $filename = $path . Rhymix\Framework\Security::getRandom(32, 'hex') . '.' . $ext; + if($manual_insert) { @copy($file_info['tmp_name'], $filename); if(!file_exists($filename)) { - $filename = $path . Rhymix\Framework\Security::getRandom(32, 'hex') . '.' . $ext; @copy($file_info['tmp_name'], $filename); + if(!file_exists($filename)) + { + return new Object(-1,'msg_file_upload_error'); + } + } + } + elseif(starts_with(RX_BASEDIR . 'files/attach/chunks/', $file_info['tmp_name'])) + { + if (!Rhymix\Framework\Storage::move($file_info['tmp_name'], $filename)) + { + if (!Rhymix\Framework\Storage::move($file_info['tmp_name'], $filename)) + { + return new Object(-1,'msg_file_upload_error'); + } } } else { if(!@move_uploaded_file($file_info['tmp_name'], $filename)) { - $filename = $path . Rhymix\Framework\Security::getRandom(32, 'hex') . '.' . $ext; - if(!@move_uploaded_file($file_info['tmp_name'], $filename)) return new Object(-1,'msg_file_upload_error'); + if(!@move_uploaded_file($file_info['tmp_name'], $filename)) + { + return new Object(-1,'msg_file_upload_error'); + } } } + // Get member information $oMemberModel = getModel('member'); $member_srl = $oMemberModel->getLoggedMemberSrl(); diff --git a/modules/file/lang/en.php b/modules/file/lang/en.php index b9321ddea..56f452543 100644 --- a/modules/file/lang/en.php +++ b/modules/file/lang/en.php @@ -44,6 +44,7 @@ $lang->file_search_target_list['isvalid'] = 'Status'; $lang->msg_not_allowed_outlink = 'It is not allowed to download files from sites other than this.'; $lang->msg_not_permitted_create = 'Failed to create a file or directory.'; $lang->msg_file_upload_error = 'An error has occurred during uploading.'; +$lang->msg_upload_invalid_chunk = 'An error has occurred during chunked uploading.'; $lang->no_files = 'No Files'; $lang->file_manager = 'Manage selected files'; $lang->selected_file = 'Selected files'; diff --git a/modules/file/lang/ko.php b/modules/file/lang/ko.php index c115b4d7c..541f392b1 100644 --- a/modules/file/lang/ko.php +++ b/modules/file/lang/ko.php @@ -45,6 +45,7 @@ $lang->file_search_target_list['isvalid'] = '상태'; $lang->msg_not_allowed_outlink = '외부링크에서 다운로드할 수 없습니다.'; $lang->msg_not_permitted_create = '파일 또는 디렉터리를 생성할 수 없습니다.'; $lang->msg_file_upload_error = '파일 업로드 중 에러가 발생하였습니다.'; +$lang->msg_upload_invalid_chunk = '분할 업로드 처리 중 오류가 발생하였습니다.'; $lang->no_files = '파일이 없습니다.'; $lang->file_manager = '선택한 파일 관리'; $lang->selected_file = '선택한 파일';