logo

파일 업로드 프론트엔드 구현

Client Side January 07, 2020

프론트단 파일업로드를 구현하는도중 여러 파일을 선택하고 관리하기위해 input type=file을 제어하는 소스코드를 생성해보았다.

 

원리는 버튼 하나에 input file을 겹쳐놓아 한개 씩 파일 업로드를 받고 업로드가 완료되면 새 input file 태그를 복제해 기존 태그위에 겹쳐놓는다. 그러면 버튼은 새로 복제된 비어있는 input file에 또 적재하게되는 원리이다.

 

일반적으로는 input file 태그를 추가하는 방식으로 기존에 많이 이용한 부분을 좀 직관적인 ui로 변경해본 케이스이다.

아래 예제코드로 파일을 넘기게 되면 $_FILES['REQ_FILE'] 배열에 순차적으로 파일이 넘어오게된다.

 

 

아직까진 실험적인 부분이 많습니다. (한번에 다중파일 선택은 제어해야할 변수가 너무 많아서 일단 보류)

 

update.php

1
2
3
4
5
6
7
8
<div class="btn-file-upload">
  <div class="btn btn-block theme-green">
    <span>파일 선택</span>
    <input type="file" id="REQ_FILE" name="REQ_FILE[]">
  </div>
  <small class="form-text text-muted">확인 버튼을 눌러야 선택한 파일이 업로드 됩니다.</small>
</div>
 
cs

 

script-file.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
$(function(){
  // 파일 업로드 제어
  let counter = 0;
  $('#REQ_FILE').on('change'function(e) {
    if (e.target.files.length > 0) {
      let newId = $(this).prop('id'+ '_' + counter++;
      let file = $(this).prop('files')[0];
      let fileName = encodeURIComponent(file.name); // 한글 파일명 대응
      let fileSize = file.size;
      let uri = '/ajax/file-list.php?file_name=' + fileName + '&file_size=' + fileSize + '&input_file=' + newId;
      // 파일 리스트 추가 및 삭제 이벤트 할당
      $('.file-list').append($('<li class="pending">').load(uri, function() {
        $(this).find('.btn-cancel-file').first().on('click'function() {
          let id = $(this).data('id');
          $(id).remove();
          $(this).closest('li').remove();
        });
      }));
      // 파일폼 복제 후 새 파일폼으로 교체. 나중에 추가된(비어있는) 폼이 우선적으로 선택됨
      $(this).after($(this).clone(true).val(''));
      $(this).prop('id', newId);
    }
  });
  
  // 파일 삭제
  $('.file-list .btn-file-remove').on('click'function() {
    if (confirm('정말로 삭제하시겠습니까?')){
      let action = 'remove-file';
      let key = $(this).data('key');
      let list = $(this).closest('li');
      $.post('_update.php', {ACTION: action, REQ_KEY: key}, function(data) {
        if (data === 'done') {
          list.remove();
        } else {
          alert('삭제처리 도중에 문제가 발생했습니다.');
        }
      });
    }
  });
  
});
 
cs

 

ajax/file-list.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$file_name = $_GET['file_name'];
$file_size = $_GET['file_size'];
$input_file = $_GET['input_file'];
?>
 
<hr>
<div class="d-flex align-items-center">
  <span class="file-icon"><?= get_icon_by_extension($file_name?></span>
  <div class="file-info">
    <div class="file-name"><?= $file_name ?></div>
    <span class="file-size"><?= number_format($file_size / 10485762) . ' MB' ?></span>
    <span class="file-date">업로드 대기 중</span>
  </div>
  <div class="file-func">
    <a href="#" class="btn-cancel-file" data-id="#<?= $input_file ?>"><i class="fas fa-fw fa-times"></i></a>
  </div>
</div>
 
cs

 

실제 적용 화면