본문으로 바로가기

abc 업로드 컴포넌트

category 웹/웹.php.asp 2008. 2. 27. 17:24
Dim abc, oFile
Set abc = Server.CreateObject("ABCUpload4.XForm")

그리고, 폼에서 인코딩 타입이 바이너리로 지정되게 되면, 이 폼에서 전송된 값을 얻어오기 위해서는 더이상 Request 객체를 사용할 수가 없고, 대신 업로드 컴포넌트의 제공되는 메소드로 그값을 얻어와야 하기에, ABCUpload 컴포넌트의 경우는 그 메소드의 이름이 item 이기에 그 메소드를 사용해서 각각의 값들을 얻어오는 다음 코드를 보실 수가 있을 것이랍니다. ^^

Dim name, mail, title, url, memo, pwd, ipaddr
name = abc.item("name")
mail = abc.item("mail")
title = abc.item("title")
url = abc.item("url")
memo = abc.item("memo")
ipaddr = abc.item("ipaddr")
pwd = abc.item("pwd")

ipaddr = abc.item("ipaddr") 라는 부분인데요. 이 부분은 현재 이글을 작성한 클라이언트의 IP 주소를 남기기 위한 것이지요. 사실, 이 부분은 이전에는 다음과 같은 코드로써 존재했었습니다.

<input type="hidden" name= "ipaddr"
       value="<%=Request.ServerVariables("REMOTE_ADDR")%>">

전페이지에서 히든값으로 넘겨준것 받아오기


Set oFile = abc("attachFile")(1)

 이는 폼에서 넘어온 파일을 oFile 이라는 이름의 변수에다가 저장하는 부분입니다. 이로써 바이너리 파일은 oFile 이라는 변수에 모두 저장이 된 것이지요...  ^^  사실상 abc("attachFile")(1) 라는 코드가 리턴해주는 객체는 ABCUpload 에서 지원하는 XField 라는 객체입니다. 해서 oFile 이라는 변수에 로드된 것은 실제로는 XField 의 모습을 하고 있지요. 그러므로 우리는 oFile 이라는 객체변수를 통해서 XField의 모든 프로퍼티와 메소드를 사용할 수가 있게 됩니다.



'실제적인 파일 업로드를 처리하는 부분
If oFile.FileExists Then
    strFileName = oFile.SafeFileName
    FileSize = oFile.Length
    FileType = oFile.FileType
    if oFile.Length > 4096000 then
        Response.Write "<script language=javascript>"
        Response.Write "alert(""4M 이상의 사이즈인 파일은 업로드하실 수 없습니다"");"
        Response.Write "history.back();"
        Response.Write "</script>"
        Response.end
    else
        strFileWholePath = GetUniqueName(strFileName, DirectoryPath)
        oFile.Save strFileWholePath
    End if
End if
'파일 업로드 처리 완료..


파일이 먼저 서버에 저장된 다음에 데이터베이스에 그 정보를 저장하는 것이 말이 맞기에, 일단 먼저 파일을 저장하는데요. 이러한 작업은 파일이 모두 제대로 넘어왔다는 가정하에서 진행되어야 하기에 소스의 시작은 oFile.FileExists 라는 코드로 시작합니다. 이 프로퍼티는 제대로 객체변수에 파일이 올라와 있는지를 알려주는 프로퍼티 입니다. 이 값이 True라면 이제 믿고 파일을 서버에 저장해도 되는 것이지요.

그리고는 이제 파일명을 strFileName = oFile.SafeFileName 을 통해서 얻어내어 strFileName  라는 변수에 담도록 합니다. 그리고, 이어지는 코드로써 파일의 크기와 타입을 얻어내고 있습니다.

그리고, 만일 파일의 크기가 4M를 넘어선다면 서버의 부하를 줄이는 한 방편으로 업로드를 하지 못하도록 저는 정책적으로 정하고 있습니다. 또한, 제가 사용하고 있는 ABCUpload 컴포넌트는 5M이상(정확한 크기는 모르겠습니다만)이 되어지면 이상한 에러를 내면서 업로드가 Fail 하게 되더라구요. 현재 4.1 버전이상이 나와있는 것으로 압니다.. 어쩌면 그 버전에서는 fiX 되었는지도 모르겠네요 ^^

어쨋든 해서 4M 가 넘어서면 자바스크립트를 통해서 경고메시지를 보내고, 폼으로 돌려보내는 것이랍니다. 그리고, 만일 용량이 4M 이하여서 문제가 없다면 else 문을 통해서 이제 파일을 실제로 업로드 하는 것이지요.

oFile.Save strFileWholePath 라는 부분이 바로 실제로 파일을 저장하는 것을 나타내는 소스입니다만



GetUniqueName 라는 함수는 페이지 하단에 따로이 만들어 두었습니다. 이것을 따로 함수로 만들어 둔 것은 소스의 가독성을 높이기 위함이며, 혹시 있을지 모르는 재사용성에 대비하기 위함이지요. 해서 저는 이렇듯, GetUniqueName라는 이름으로 현재 업로드하려는 파일과 같은 이름의 파일이 이미 Uploaded_Files 라는 폴더에 있는지 검사해서 있다면 그 이름을 약간 바꾸어 처리하는 로직의 함수를 만들어 둔 것입니다.

즉, 이미 Xfile.zip 이라는 파일이 존재하고 있는데, 우연히도 어떤 사람이 같은 이름의 파일을 저장하고자 할 경우에 이것이 덮어쓰여질 문제를 해결하기 위해서, 새로이 올라오는 Xfile.zip을 Xfiles(1).zip 이라고 저장하도록 하는 것이지요. 윈도우즈가 그렇게 하듯이 말입니다.

사실, 이 함수는 이미 인터넷에 공개되어져서 출처를 정확히 알 수 없는 상태로 떠돌고 있던 소스를 잡아다가 제가 양념만 조금 뿌려서 살짝 데친 것이기에... 무명씨인 그 원본자에게 감사하는 마음으로 사용하고 있습니다.

그러면, 이 함수를 한번 알아보겠습니다. 이 함수는 일단 두개의 인자를 요구합니다. 첫번째 인자는 사용자가 업로드 하고자 하는 파일의 파일명이어야 합니다. 두번째 인자는 파일이 업로드될 서버의 디렉토리경로명입니다. 이 두가지를 가지고서 함수는 뚝딱뚝딱 어떤 처리를 하고, 서버에 저장될 완전한 유니크한 이름의 파일전체 경로명을 리턴해 줄 것입니다.

다시 말해, 사용자가 업로드 하고자 하는 파일명이 XYZ.zip 이고, 서버에 저장될 업도르 파일 디렉토리가 C:\Inetpub\wwwroot\Web\Uploaded_Files 라고 했을 때,

서버에 아직 XYZ.zip이라는 이름의 파일이 존재하지 않고 있다면 이 함수는 리턴 경로로써 C:\Inetpub\wwwroot\Web\Uploaded_Files\XYZ.zip 을 넘겨줄 것이고,

만일, 서버에 이미 XYZ.zip 이라는 이름의 파일이 존재하고 있다면 이 함수는 리턴 경로로써 C:\Inetpub\wwwroot\Web\Uploaded_Files\XYZ(1).zip 을 넘겨줄 것이라는 이야기입니다.

그리고, 이미 XYZ.zip과 XYZ(1).zip이 모두 존재하고 있다면 이 함수는 리턴경로로써
C:\Inetpub\wwwroot\Web\Uploaded_Files\XYZ(2).zip 을 넘겨줄 것이라는 이야기입니다.

어떻게 이 함수로 그런 일을 처리하는지 함수를 한번 살펴봅시다.

Function GetUniqueName(byRef strFileName, DirectoryPath)

    Dim strName, strExt
    strName = Mid(strFileName, 1, InstrRev(strFileName, ".") - 1) ' 확장자를 제외한 파일명을 얻는다.
    strExt = Mid(strFileName, InstrRev(strFileName, ".") + 1) '확장자를 얻는다

    Dim fso
    Set fso = Server.CreateObject("Scripting.FileSystemObject")

    Dim bExist : bExist = True
    '우선 같은이름의 파일이 존재한다고 가정
    Dim strFileWholePath : strFileWholePath = DirectoryPath & "\" & strName & "." & strExt
    '저장할 파일의 완전한 이름(완전한 물리적인 경로) 구성
    Dim countFileName : countFileName = 0
    '파일이 존재할 경우, 이름 뒤에 붙일 숫자를 세팅함.

    Do While bExist ' 우선 있다고 생각함.
        If (fso.FileExists(strFileWholePath)) Then ' 같은 이름의 파일이 있을 때
            countFileName = countFileName + 1 '파일명에 숫자를 붙인 새로운 파일 이름 생성
            strFileName = strName & "(" & countFileName & ")." & strExt
            strFileWholePath = DirectoryPath & "\" & strFileName
        Else
            bExist = False
        End If
    Loop
    GetUniqueName = strFileWholePath
End Function

먼저, 함수는 첫번째 인자로 넘어온 파일명에서 파일이름과 확장자를 각각 뽑아내어서 변수에 저장하도록 하고 있습니다.

그리고, FSO 개체를 생성하고(단지, FileExists 라는 유용한 함수를 사용하기 위해서), strFileWholePath  라는 경로에 두번째 인자와 첫번째 인자를 합쳐서 일단 전체경로를 가볍게 만들어 봅니다.

해서, FSO의 FileExists 메소드를 통해서 이 전체경로와 일치하는 파일이 이미 있는지 살펴보아서 만일 이러한 경로의 파일이 존재하지 않는다면 그대로 이를 사용하면 될 것이고, 만일 같은 이름의 파일이 이미 존재한다면 파일명뒤에다가 루프를 돌면서 (1), (2), (3)... 과 같은 식으로 넘버를 추가하는 것이지요. 같은 이름의 파일이 존재하지 않는 번호가 나올 때까지 말입니다. 어렵지는 않은 내용이지요?

그렇습니다. 모든 과정이 다 끝난 다음에는 GetUniqueName = strFileWholePath 를 통해서 그 만들어진 경로를 리턴하도록 하고 있습니다. ^^ 이제... 이 경로 그대로 파일을 저장하면 되는 것이지요.

해서 우리의 소스에서는 이 함수를 이용하여

strFileWholePath = GetUniqueName(strFileName, DirectoryPath)
oFile.Save strFileWholePath

라는 두줄로 이 모든 것을 해결한 것이랍니다