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;
            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 파일을 참고해서 처리했다.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.