사이트 내 전체검색
PHP
SWFUpload 로 업로드 구현
로빈아빠
https://cmd.kr/php/749 URL이 복사되었습니다.

본문

SWFUpload 로 업로드 구현(1) - 개요

 

파일 멀티 업로드 및 업로드 진행바등의 구현 필요성으로 인해 SWFUpload로 파일 업로드를 구현하기로 함.

PHP, MySQL 을 이용하여 구현.

 

[다운로드]

SWFUpload v2.2.0.1 Core.zip

SWFUpload v2.2.0.1 Samples.zip

 

SWFUpload는 플래쉬로 파일 업로드를 구현을 하고 업로드에 진행 및 완료에 관한 정보를 자바스크립트 이벤트를 통해

제공하여 웹페이지에 표시할 수 있도록 함. 위의 과정이 페이지 새로 고침없이 Backend로 진행됨.

자바스크립트와 별개로 Backend로 진행되는 파일저장 및 폼 전송후 동작은 서버사이드 언어로 구현해야 한다.

 

파일업로드는 다음과 같은 기능을 갖추도록 함.

  1. 지정한 개수만큼 파일 업로드 가능
  2. 업로드 진행상황이 보여야 함
  3. 업로드 도중에 취소 가능
  4. 업로드 완료후 취소 가능

 

모든 코드를 새로 작성하기는 시간낭비라 생각되어 예제중 가장 비슷한 동작을 하는 예제를 변형하여 쓰기로 함.

예제 중 simpledemo 에 사용된 자바스크립트 및 CSS 파일 이용 (SWFUpload v2.2.0.1 Samples\demos\simpledemo)

 

파일 및 디렉토리 구성

/swfupload/upload.html : 업로드 폼 파일 (새로 작성)

/swfupload/php/upload.php : Backend로 작동되어 업로드 된 파일을 임시로 저장 및 임시 DB 테이블에 기록 (새로 작성)

/swfupload/php/save.php : 폼 전송후 기타 폼값 저장 및 임시로 업로드 된 파일을 저장하고 임시 파일 및 임시 DB자료를 삭제(새로 작성)

/swfupload/swf/swfupload.swf : 플래쉬 업로드 파일 (SWFUpload Core)

/swfupload/js/jquery.js : jquery 자바스크립트 프레임 워크

/swfupload/js/swfupload.js : 플래쉬 객체를 정의해 놓은 자바스크립트 파일(SWFUpload Core)

/swfupload/js/fileprogress.js : 진행바 및 상태창 관련 자바스크립트 파일 (simpledemo 파일을 변경하여 사용)

/swfupload/js/handlers.js : 이벤트 관련 자바스크립트 파일(simpledemo 파일을 변경하여 사용)

/swfupload/js/swfupload.queue.js : 큐관련 자바스크립트 파일(simpledemo 파일)

/swfupload/js/upload.js : upload.html 관련 자바스크립트 파일(새로 작성)

/swfupload/css/default.css : CSS 파일 (예제파일에 공통적으로 사용된 파일 SWFUpload v2.2.0.1 Samples\demos\css\default.css)

/swfupload/images/searchbutton.gif : 플래쉬 영역에 포일 이미지(새로 제작)

/swfupload/images/cancelbutton.gif : 업로드 취소에 사용될 이미지 (SWFUpload v2.2.0.1 Samples\demos\images\cancelbuton.gif)

/upload/temp/ : 업로드 임시파일을 저장할 디렉토리

/upload/ : 업로드 파일을 저장할 디렉토리

 

DB 테이블 구성 (MySQL)

 

임시테이블 (upload_temp)

CREATE TABLE `upload_temp` (
  `UID` int(11) NOT NULL AUTO_INCREMENT,   # primary key
  `UNIQUE_KEY` varchar(255) DEFAULT NULL,  # 업로드 세션 아이디를 저장
  `FILE_NAME` varchar(255) DEFAULT NULL,    # 파일의 원래 이름
  `REAL_NAME` varchar(255) DEFAULT NULL,   # 임의로 저장된 실제 파일명
  `SAVE_TIME` int(11) DEFAULT NULL,             # 저장시간

# (업로드만 하고 폼전송을 안한경우 필요없는 파일이 쌓이게 된다 이를 구분하여 삭제하기 위해 저장시간을 기록해둔다)

# 저장시간은 unix timestamp 형식으로 하기 위해 int형으로 하였다.
  PRIMARY KEY (`UID`)
) DEFAULT CHARSET=utf8; 

 

파일저장테이블(upload)

파일 저장용 테이블은 최대한 간단하게 구현.

실제 웹사이트에 사용하려면 파일 소유자 등등 기타 정보가 더 필요할 것이다.

CREATE TABLE `upload` (
  `UID` int(11) NOT NULL AUTO_INCREMENT, # primary key
  `FILE_NAME` varchar(255) DEFAULT NULL, # 파일의 원래 이름
  `REAL_NAME` varchar(255) DEFAULT NULL, # 임의로 저장된 실제 파일명
  `SAVE_TIME` int(11) DEFAULT NULL, # 저장시간 unix timestamp
  PRIMARY KEY (`UID`)
) DEFAULT CHARSET=utf8;

 

사용 이미지

searchbutton.gif

download?fid=6422268405d2f14b300426842025ebf3&name=searchbutton.gif

 

cancelbutton.gif

download?fid=6422268405d2f14b98b6268420a3c9f3&name=cancelbutton.gif 

 

/////////////////////////////////////////////////////////////////

SWFUpload 로 업로드 구현(2) - upload.html (폼 파일)

 

<?php

/* upload.html */
session_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>SWFUpload</title>
    <link rel="stylesheet" href="/swfupload/css/default.css" />

    <script type="text/javascript" src="/swfupload/js/jquery.js"></script>

    <script type="text/javascript" src="/swfupload/js/swfupload.js"></script>
    <script type="text/javascript" src="/swfupload/js/fileprogress.js"></script>
    <script type="text/javascript" src="/swfupload/js/handlers.js"></script>
    <script type="text/javascript" src="/swfupload/js/swfupload.queue.js"></script>
    <script type="text/javascript" src="/swfupload/js/upload.js"></script>
</head>
<body>
    <form id="uploadForm" action="/swfupload/php/save.php" method="post" enctype="multipart/form-data">
        <!-- 최대 업로드 파일 수 -->
        <input type="hidden" id="maxFileNum" name="maxFileNum" value="5" />
        <!-- 최대 파일 용량 -->
        <input type="hidden" id="maxFileSize" name="maxFileSize" value="20 MB" />
        <!-- 업로드 세션 구분용 -->
        <input type="hidden" id="unique_key" name="unique_key" value="<?=hash('md5', microtime())?>" />

        <!-- 파일명을 표시할 텍스트 박스 -->
        <input type="text" id="txtFileName" />
        <!-- 플래쉬 파일로 대체될 영역(파일찾기 버튼) -->
        <span id="spanSWFUploadButton"></span>
        <!-- 전송중지 버튼 -->
        <input id="btnCancel" type="button" value="전송중지" />
        <!-- 파일전송 상태를 보여줄 부분 -->
        <div id="fsUploadProgress"></div>
        <div><input type="submit" value="저장" /></div>
    </form>
</body>
</html>

 

각종 설정 값들은 swfupload 객체를 생성할때 직접 적어주면 되지만 자바스크립트 외부에서 설정값을 두어

좀더 유연하게 활용하기 위해 폼안에 히든값으로 저장하였다.

파일업로드 세션 구분을 위해 랜덤값을 지정해 주었다.

 

실행화면

아직 swfupload 객체를 생성하지 않았으므로 플래쉬 버튼은 보이지 않는다.

download?fid=64222684d8a31c4bdab62684e009c6df&name=screenshot1.jpg

 

 

/////////////////////////////////////////////////////////////////////////////////////

 

SWFUpload 로 업로드 구현(3) - upload.js

 

simpledemo 에 있는 index.php 파일 내에 포함되어있는 자바스크립트 파일을 수정하여 작성하였다.

 

// upload.js 파일

var swfu; // 업로드 플래쉬 객체

$(document).ready(function(){

    // SWFUpload 객체 설정값 지정
    var setting = {
        // 업로드 세션 구분을 위해 랜덤값을 GET 으로 전달했다.
        upload_url : "/swfupload/php/upload.php?unique_key=" + $("input#unique_key").val(),

        flash_url : "/swfupload/swf/swfupload.swf",

        file_post_name : "Filedata",

        file_upload_limit : parseInt($("input#maxFileNum").val()), // 파일 전송 최대 개수 upload.html 에 지정되어 있음

        button_placeholder_id : "spanSWFUploadButton", // 플래쉬로 교체될 DOM 엘레멘트
        button_image_url : "/swfupload/images/searchbutton.gif", // 플래쉬에 보여줄 버튼 이미지
        button_width : 66,
        button_height : 22,

        // The event handler functions are defined in handlers.js
        file_queued_handler : fileQueued,
        file_queue_error_handler : fileQueueError,
        file_dialog_complete_handler : fileDialogComplete,
        upload_start_handler : uploadStart,
        upload_progress_handler : uploadProgress,
        upload_error_handler : uploadError,
        upload_success_handler : uploadSuccess,
        upload_complete_handler : uploadComplete,
        queue_complete_handler : queueComplete, // Queue plugin event

        file_size_limit : $("input#maxFileSize").val(), // 파일 전송 최대 크기 upload.html 에 지정되어있음

        custom_settings : {
           progressTarget : "fsUploadProgress",
           cancelButtonId : "btnCancel"
        },

        // Debug settings
        debug: true // 디버그를 위해 설정해 줌
       }

     swfu = new SWFUpload(setting); // SWFUpload 객체 생성

 

     // 업로드 취소버튼에 클릭 이벤트 핸들러 등록, 기본적으로 disabled 설정
     var btnCancel = $("input#btnCancel");
     btnCancel.attr("disabled",true);
     btnCancel.click(function(){
        cancelQueue(upload1);
     });

 

     // 폼체크
     // 전송된 파일이 없으면 폼전송을 하지 않음
     // SWFUpload에 의해 전송이 되면 폼 하위에 히든 엘레멘트로 전송 파일 아이디를 넣어줌
     // (히든 엘레멘트의 클래스를 uploadedfile로 통일)
     $("form#uploadForm").submit(function(){
        if ($("input.uploadedfile").length == 0) {
            alert("업로드된 파일이 없습니다.");
            return false;
        }
    });
});

 

upload.html 실행결과(자바스크립트 오류 확인을 위해 Firefox에서 Firebug를 활성화 한 상태에서 실행하였다)

download?fid=64222687b8998a4ba1492687c2e01b7c&name=screenshot2.jpg

 

SWFUpload객체를 생성하였기 때문에 플래쉬 버튼이 보인다.

또한 객체 생성시 세팅값에 Debug : true 로 변경하였기 때문에 하단에 상태 표시창이 하나 생겼다. 실제 작동시에는 false로 변경할 것이다.

 

아직가지는 몇가지 문제가 있다.

  • 우선 자바스크립트 오류가 나는데 simpledemo에서는 업로드 되면 상태를 id가 status인 레이어에 표시해 주는데
    uplaod.html 에 이를 만들지 않았기 때문이다.
  • 파일선택후 선택한 파일명이 텍스트 박스에 나오지 않는다.
  • 업로드 상태표시창에 메시지가 영어로 나오는데 한글로 바꿀 필요가 있다.
  • 마지막으로 업로드 완료후 업로드 상태표시창이 일정시간이 지나면 사라지는데 이를 변경하여 사라지지 않고 클릭하여
    업로드 취소를 할 수 있도록 만들것 이다.
  • 업로드가 완료가 되어도 폼 전송시 전송이 되지 않는다.

위의 문제는 /swfupload/js/handlers.js 와 /swfupload/js/fileprogress.js 두개의 파일을 수정하여 해결할 것이다.

 

//////////////////////////////////////////////////////////////////////////////////////

 

SWFUpload 로 업로드 구현(4) - handles.js, fileprogress.js

 

업로드 관련 핵심파일인 handles.js 파일과 fileprogress.js 파일을 수정하고자 한다.

handles.js는 SWFUpload가 발생시키는 이벤트에 따라 사용자가 알아볼 수 있도록

화면에 보여주는 역할을 한다.

fileprogress.js는 업로드 진행 상황에 따른 메시지를 웹페이지에 보여주는 역할을 한다.

 

상태 메시지등은 handles.js 파일 안에 있으므로 이를 수정하여 메시지를 한글로 바꿀 것이다.

수정하기 전에 파일 저장시 문자코드를 UTF-8로 변경하여야 한다. upload.html 파일의 문자코드를

UTF-8로 지정했으므로 이 곳도 맞춰 주어야 한글이 깨지지 않고 보여지게 된다.

이전 단계에서 발생했던 문제들을 하나씩 해결해보자.

메시지의 한글화 부분은 생략하기로 한다.

 

- 자바스크립트 오류

id가 status인 엘레멘트가 없어서 나는 오류였다. upload.html 에 엘레멘트를 만들지 않을 것이므로

handles.js 파일에서 다음 부분을 주석 처리해 준다. (이미 upload.html에 queueComplete 함수를

사용할 것으로 선언하였으므로 함수 자체를 주석처리하면 오류가 난다)

 

function queueComplete(numFilesUploaded) {
// var status = document.getElementById("divStatus");
// status.innerHTML = numFilesUploaded + " file" + (numFilesUploaded === 1 ? "" : "s") + " uploaded.";

}

 

- 파일선택후 선택한 파일명이 텍스트 박스에 나오지 않는다.

이는 <input type="file />의 형식이 아니므로 텍스트 박스에 파일명은 수동으로 지정해 주어야 한다.

멀티파일업로드가 가능하므로 파일이 선택됐을때가 아니라 업로드 시작시 파일명이 텍스트 박스에 보여지고

완료시 파일명이 사라지게 하도록 한다.

handles.js의 다음 부분을 수정하도록 한다.

 

// 전송 시작시 호출되는 자바스크립트 함수

function uploadStart(file) {
    try {
        /* I don't want to do any file validation or anything,  I'll just update the UI and
        return true to indicate that the upload should start.
        It's important to update the UI here because in Linux no uploadProgress events are called. The best
        we can do is say we are uploading.
        */
        var progress = new FileProgress(file, this.customSettings.progressTarget);
        progress.setStatus("전송중...");
        progress.toggleCancel(true, this);
        $("input#txtFileName").val(file.name); // 텍스트 필드에 업로드중인 파일명을 표시
    }
    catch (ex) {}
    return true;
}

 

...

 

// 전송 성공시 실행되는 자바스크립트 함수

function uploadSuccess(file, serverData) {
    try {
        var progress = new FileProgress(file, this.customSettings.progressTarget);
        progress.setComplete();
        progress.setStatus("전송완료");
        progress.toggleCancel(false);
        $("input#txtFileName").val(""); // 텍스트 필드 값 지움
    } catch (ex) {
        this.debug(ex);
    }
}


- 전송완료후  일정시간이 지나면 상태표시창이 사라짐

fileprogress.js 다음 부분을 주석처리하여 주도록 한다.

// 전송 상태창이 완료 됐음으로 바꾸어줌

FileProgress.prototype.setComplete = function () {
    this.fileProgressElement.className = "progressContainer blue";
    this.fileProgressElement.childNodes[3].className = "progressBarComplete";
    this.fileProgressElement.childNodes[3].style.width = "";

    //var oSelf = this;
    //this.setTimer(setTimeout(function () {
    //    oSelf.disappear();
    //}, 10000));

};

 

- 전송완료후 상태표시창에 취소 버튼(buttoncancel.gif)이 보이지 않음

handlers.js 에서 다음부분을 수정하여 주도록 한다.

function uploadSuccess(file, serverData) {
    try {
        var progress = new FileProgress(file, this.customSettings.progressTarget);
        progress.setComplete();
        progress.setStatus("전송완료");
        progress.toggleCancel(true); // 취소 버튼(cancelbutton.gif)을 보여줌

        $("input#txtFileName").val("");
    } catch (ex) {
    this.debug(ex);
    }
}

 

오류사항 외에 다음 기능을 추가하여야 한다.

- 임시 업로드 된 파일 중 실제 저장할 파일을 POST로 전달할 수 있게 폼변수 지정

- 전송완료 후 취소시 POST로 저장한 폼 변수 삭제

 

// 전송 성공시 호출되는 자바스크립트 함수

function uploadSuccess(file, serverData) {
    try {
        var progress = new FileProgress(file, this.customSettings.progressTarget);
        progress.setComplete();
        progress.setStatus("전송완료");
        progress.toggleCancel(true);

        $("input#txtFileName").val("");
  
        // 폼에 히든 엘리먼트 추가
        var uploadedFile = document.createElement("input");
        uploadedFile.id = "input_" + file.id; // 엘레멘트 아이디
        uploadedFile.name = "uploadedFile[]"; // 엘레멘트 이름 PHP에서 배열로 받기위해 []를 사용
        uploadedFile.className = "uploadedfile"; // 엘레멘트 클래스 명 jquery에서 히든값을 손쉽게 체크하기 위해 지정
        uploadedFile.type = "hidden";
        uploadedFile.value = serverData; // 폼 변수값은 upload.php에서 리턴해주는 값을 저장한다. 실제저장되어 있는 임시 파일명

        document.getElementById("uploadForm").appendChild(uploadedFile); // 폼 변수 값 추가
  
        progress.fileProgressElement.childNodes[0].onclick=function(){
            // 취소버튼 클릭시 전송된 파일명을 저장하고 있는 히든 엘리먼트 삭제
            if (confirm("전송된 파일 \'" + file.name + "\'을 삭제하시겠습니까?")) {
                document.getElementById("uploadForm").removeChild(document.getElementById("input_" + file.id));
                progress.setTimer(setTimeout(function () {
                    progress.disappear();
                }, 300));
                swfu.setFileUploadLimit(swfu.getSetting("file_upload_limit")+1); // 파일전송 가능 개수를 1개 늘림
            }
        }
    } catch (ex) {
        this.debug(ex);
    }
}

 

upload.html 실행결과

download?fid=6422268c447e0b4cab54268c5195bd36&name=screenshot3.jpg

 

 

/////////////////////////////////////////////////////////////////////////////////

 

SWFUpload 로 업로드 구현(5) - upload.php

 

upload.php 파일은 플래쉬 객체를 통해 업로드한 파일을 임시로 저장하고 DB에 그 내용을 기록한 후

저장한 파일명을 되돌려 주는 역할을 한다.

 

<?php
session_start();

 

// DB 설정 부분

$host = "localhost";
$db_id = "root";
$db_pwd = "1234";
$db_name = "upload_test";

 

// DB 연결

$dbcon = mysql_connect($host,$db_id,$db_pwd);
mysql_select_db($db_name,$dbcon);

$query = "set names utf8";
mysql_query($query,$dbcon);

 

// 임시 업로드 디렉토리 설정

$upload_temp_dir = $_SERVER['DOCUMENT_ROOT'] . "/upload_temp";

 

// 파일전송이 제대로 되지 않으면 오류

if (!isset($_FILES["Filedata"]) || !is_uploaded_file($_FILES["Filedata"]["tmp_name"]) || $_FILES["Filedata"]["error"] != 0) {
    header("HTTP/1.1 500 File Upload Error");
    if (isset($_FILES["Filedata"])) {
        echo $_FILES["Filedata"]["error"];
    }
    exit(0);
}

 

$file_name = strtolower($_FILES['Filedata']['name']); // 원래 파일명
$file_ext = strtolower(substr(strrchr($file_name, "."), 1)); // 파일 확장자

do { // 임의의 중복되지 않는 화일명을 구한다.
    $new_file_name = rand(1000000,9999999) . "." . $file_ext;
    if (!file_exists($upload_temp_dir . "/" . $new_file_name)) {
        break;
    }
} while(1);

 

if (move_uploaded_file($_FILES['Filedata']['tmp_name'], $upload_temp_dir . "/" . $new_file_name)) {
    $query = "insert into `upload_temp`(`UNIQUE_KEY`,`FILE_NAME`,`REAL_NAME`,`SAVE_TIME`";
    $query .= ") values(";
    $query .= "'{$_GET['unique_key']}', '$file_name', '$new_file_name', unix_timestamp()";
    $query .= ")";

 

    // 임시 테이블에 자료를 입력한다.
    if (mysql_query($query, $dbcon)) {

        // 업로드 성공하면 파일명을 반환

        echo($new_file_name);
    } else {
        header("HTTP/1.1 500 File Upload Error");
        echo("Query Error");
    }
} else {
    header("HTTP/1.1 500 File Upload Error");
    echo("Unhandled Error");
}

?>

 

다음은 임시 업로드 완료 후 DB 상태임

download?fid=64222696273d184c61c7269662e1cefc&name=screenshot4.jpg

 

 

1~4, 5~8 은 세션아이디는 같지만 UNIQUE_KEY가 다르므로 다른 업로드 세션에서 업로드 된 것이다.

참고로 임시 업로드 완료후 삭제한 파일도 전부 기록되어 있어 있는데 업로드 완료후 삭제는 실제로 삭제한 것이아니라

폼값만 변경해 준 것이므로 이의 처리는 save.php 에서 하게 될 것이다.(전송중에 취소는 DB에 남아있지 않는다)

 

[출처]http://www.cyworld.com/psykey/3092714

댓글목록

등록된 댓글이 없습니다.

PHP
871 (5/18P)

Search

Copyright © Cmd 명령어 3.147.75.46