jQuery File Upload 를 이용한 파일 업로드 커스터마이징
최근의 작업 중에 대용량 파일을 업로드할 필요성이 있어 관련 플러그인을 서치 후 사용하게 된 jQuery File Upload 이다. 큰 파일의 경우 여러 개의 파일로 쪼개서 업로드 하기 때문에 서버 용량이 허용하는 한 파일을 업로드할 수 있다. 중간에 오류가 나지 않는다는 전제하에서 말이다. 그리고 파일 업로드가 ajax 로 처리 되기 때문에 시각적으로도 좋은 점이 있다.
파일 업로드가 필요한 페이지에 아래와 같이 관련 코드를 추가했다.
/css/jquery-file-upload/jquery.fileupload.css
/css/jquery-file-upload/jquery.fileupload-ui.css
/js/jquery-file-upload/vendor/jquery.ui.widget.js
/js/jquery-file-upload/jquery.iframe-transport.js
/js/jquery-file-upload/jquery.fileupload.js
/js/jquery-file-upload/jquery.fileupload-process.js
jQuery File Upload 전체 소스를 보면 위 파일 외에 다른 css, js 파일도 있지만 위의 파일만 사용해도 문제는 없다. 디자인 요소를 과감하게 빼버린 탓에.. 개발자가 디자인까지 신경쓰면.. 일이 안되니까.. ^^; 그리고 파일 업로드 페이지는 아래와 같은 마크업 구조를 가진다.
<input type="file" name="files" id="file_software" class="file-upload" data-url="http://example.com/file/upload" data-form-data='{"extra": "software"}'>
<ul class="file-list list-unstyled mb-0"></ul>
위 마크업 중 data-form-data
는 파일 업로드 때 추가적인 정보를 처리하기 위한 것으로 없어도 되는 부분이다. 그리고 디자인 부분은 부트스트랩을 사용했기 때문에 관련 css 클래스 등이 추가되어 있다. 부트스트랩을 사용하는 게 내게 최선의 방법이다. 이제 아래와 같은 코드를 추가해서 jQuery File Upload 플러그인 사용 설정을 해줘야 한다. 기본 코드 외에 몇 가지 필요한 내용이 있어 코드를 추가한 부분이 있다.
<?php
$maxUploadFileSize = getUploadMaxFileSize();
$script = <<<SCRIPT
<script>
jQuery(function() {
jQuery(".file-upload").fileupload({
dataType: "json",
maxChunkSize: $maxUploadFileSize,
sequentialUploads: false,
add: function(e, data) {
var maxFileCount = parseInt($(this).data("maxfilecount"));
if (isNaN(maxFileCount))
maxFileCount = 1;
console.log(maxFileCount);
var \$t = $(this);
var \$w = \$t.closest("div");
var \$li = \$w.find("ul.file-list li");
if (\$li.length >= maxFileCount) {
var txt = \$w.find("label").text();
alert("업로드된 " + txt + " 파일이 있습니다. 기존 파일을 삭제하신 후 새로 업로드해 주십시오.");
return false;
}
data.context = $('<li class="file my-1 row"></li>')
.append(jQuery('<div class="file-name col-md-8 text-muted"></div>').text(data.files[0].name))
.append('<div class="progress col-md-3 my-auto px-0"><div class="progress-bar progress-bar-striped bg-info" role="progressbar"></div></div>')
.append('<div class="del-button col-md-1"></div>')
.appendTo($(this).siblings(".file-list"));
data.submit();
},
progress: function(e, data) {
var progress = parseInt((data.loaded / data.total) * 100, 10);
data.context.find(".progress-bar").css("width", progress + "%");
},
done: function(e, data) {
var res = data.result.files[0];
var val = res.path;
var url = res.deleteUrl;
if (res.error !== "") {
data.context.remove();
alert(res.error);
return false;
}
jQuery(this.form)
.find("input[type=hidden]:last")
.after('<input type="hidden" name="upload[]" value="' + val + '">');
data.context
.find(".file-name")
.removeClass("text-muted")
.append(' <span class="badge badge-success"><i class="fas fa-check"></i></span>')
.end()
.find(".del-button")
.append('<button type="button" class="btn btn-sm btn-danger upload-delete" data-val="' + val + '" data-type="DELETE" data-url="' + url + '"><i class="far fa-trash-alt"></i></button>');
jQuery(this).blur();
}
});
jQuery(document).on("click", ".upload-delete", function(e) {
var \$t = jQuery(this);
var val = \$t.data("val");
var url = \$t.data("url");
var type = \$t.data("type");
jQuery.ajax({
url: url,
type: type,
success: function(data) {
\$t.closest("li").remove();
jQuery("input[name='upload[]']").each(function(i) {
var \$el = jQuery(this);
if (\$el.val() == val)
\$el.remove();
});
},
error: function(request, status, error) {
console.log("code:"+request.status+"\\n"+"message:"+request.responseText+"\\n"+"error:"+error);
},
dataType: "JSON"
});
});
jQuery(document).on("click", ".file-delete", function(e) {
if(!confirm("파일을 삭제하시겠습니까?"))
return false;
var \$t = jQuery(this);
var act = \$t.data("act");
var key = \$t.data("key");
var no = \$t.data("no");
var token = setTokenValue("", "admin");
jQuery.ajax({
url: "./filedelete.php",
data: {act: act, key: key, no: no, token: token},
success: function(data) {
if (data.error != "") {
alert(data.error);
return false;
}
\$t.closest("li").remove();
},
error: function(request, status, error) {
console.log("code:"+request.status+"\\n"+"message:"+request.responseText+"\\n"+"error:"+error);
},
dataType: "JSON"
});
});
});
</script>
SCRIPT;
echo $script;
?>
스크립트 부분만 포스팅하면 되는데.. 코드를 작업한 코드에서 바로 가져오다 보니 php 형태의 코드가 되고 말았다. 실제 사용에서는 적절하게 수정되어야 한다. 위 코드를 보면 파일 업로드 개수 체크하는 부분과 업로드 후 파일이 표시되는 부분을 커스터마이징하기 위한 내용이 주를 이룬다. 실제로 파일 업로드 후 표시되는 화면은 아래와 같다.
디자인적은 측면은 전문이 아니니까.. 잘 수정해서 사용하면 된다. 그리고 코드 중 업로드 파일을 삭제하는 코드가 있는데 이것은 두 가지로 분리해서 처리했다. 신규 글쓰기 등에서는 임시로 업로드된 파일을 삭제해야 하기 때문에 jQuery(document).on("click", ".upload-delete", function(e) {
에서 처리가 되도록 되어있고 글쓰기 완료 후 업로드된 파일은 위치를 변경해서 저장하도록 했기 때문에 jQuery(document).on("click", ".file-delete", function(e) {
에서 처리가 된다. 파일 업로드 처리 및 DB 처리 코드는 jQuery File Upload 에서 제공하는 UploadHandler.php
파일을 참고해서 처리했다.