web freer

专注web开发,支持开源精神。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

    网页上传是Web开发时经常用到的功能,对于大量文件或大体积文件的情况可以考虑调用组件解决(如前文提到的SWFUpload组件)。然而有些情况只需要传递几个文件,而且文件体积并不太大,这种情况下使用组件则有点牛刀杀鸡的感觉,通过html自带的<input type="file">表单就可以实现需要的功能,关键在于后台接收程序的处理。

    php处理上传做的很方便,上传文件的信息通过服务器自动处理到$_FILES数组中,开发者只需要使用的内置处理函数简单操作就可以啦。ASP开发者则没有这么幸运,官方并没有提供直接的处理方法,需要开发者自己设计,这时就需要开发者了解IIS对enctype="multipart/form-data"表单的处理方式,IIS把enctype="multipart/form-data"表单提交的数据存储成二进制数据,以二进制格式返回给开发者,开发者则需要通过LenB、MidB的字节处理函数来分析获取的上传内容,客户端发送的具体表单数据格式,可以了解下HTTP RFC1867协议传输格式方面的知识。

    下面是我处理多个文件上传的方法,包括php和asp两个版本。

    php:WEBSITE_DIRROOT代表网站根目录:

<?php
       /*
           * class: 文件上传类
           * author: 51JS.COM-ZMM
           * date: 2011.1.20
           * email: 304924248@qq.com
           * blog: http://www.cnblogs.com/cnzmm/
       */

       class Upload {
             public $up_ext=array(), $up_max=5210, $up_dir;
             private $up_name, $up_rename=true, $up_num=0, $up_files=array(), $up_ret=array();

             function __construct($name, $ext=array(), $rename=true) {
                 if (!empty($name)) {
                     $this->up_name = $name;
                     !empty($ext) && $this->up_ext = $ext;
                     $this->up_rename = $rename;
                     $this->up_dir = WEBSITE_DIRROOT.
                                     $GLOBALS['cfg_upload_path'];                 
                     $this->InitUpload();
                 } else {
                     exit('upload文件域名称为空,初始化失败!');
                 }
             }

             private function InitUpload() {
                 if (is_array($_FILES[$this->up_name])) {
                     $up_arr = count($_FILES[$this->up_name]);
                     $up_all = count($_FILES[$this->up_name], 1);
                     $up_cnt = ($up_all - $up_arr) / $up_arr;
                     for ($i = 0; $i < $up_cnt; $i ++) {
                          if ($_FILES[$this->up_name]['error'][$i] != 4) {
                              $this->up_files[] = array(
                                  'tmp_name' => $_FILES[$this->up_name]['tmp_name'][$i],
                                  'name' => $_FILES[$this->up_name]['name'][$i],
                                  'type' => $_FILES[$this->up_name]['type'][$i],
                                  'size' => $_FILES[$this->up_name]['size'][$i],
                                  'error' => $_FILES[$this->up_name]['error'][$i]
                              );
                          }
                     }
                     $this->up_num = count($this->up_files);
                 } else {
                     if (isset($_FILES[$this->up_name])) {
                         $this->up_files = array(
                              'tmp_name' => $_FILES[$this->up_name]['tmp_name'],
                              'name' => $_FILES[$this->up_name]['name'],
                              'type' => $_FILES[$this->up_name]['type'],
                              'size' => $_FILES[$this->up_name]['size'],
                              'error' => $_FILES[$this->up_name]['error']
                         );
                         $this->up_num = 1;
                     } else {
                         exit('没找找到需要upload的文件!');
                     }
                 }
 
                 $this->ChkUpload();
             }

             private function ChkUpload() {
                 if (empty($this->up_ext)) {
                     $up_mime = array('image/wbmp', 'image/bmp', 'image/gif', 'image/pjpeg', 'image/x-png');
                     foreach ($this->up_files as $up_file) {
                         $up_allw = false;
                         foreach ($up_mime as $mime) {
                             if ($up_file['type'] == $mime) {
                                 $up_allw = true; break;
                             }
                         } 
                         !$up_allw && exit('不允许上传'.$up_file['type'].'格式的文件!');

                         if ($up_file['size'] / 1024 > $this->up_max) {
                             exit('不允许上传大于 '.$this->up_max.'K 的文件!');
                         }
                     } 
                 } else {
                     foreach ($this->up_files as $up_file) {
                         $up_ext = end(explode('.', $up_file['name']));

                         $up_allw = false;
                         foreach ($this->up_ext as $ext) {                             
                             if ($up_ext == $ext) {
                                 $up_allw = true; break;
                             }
                         }
                         !$up_allw && exit('不允许上传.'.$up_ext.'格式的文件!');

                         if ($up_file['size'] / 1024 > $this->up_max) {
                             exit('不允许上传大于 '.$this->up_max.'K 的文件!');
                         }
                     }
                 }

                 $this->Uploading();
             }

             private function Uploading() {
                 if (IO::DIRCreate($this->up_dir)) {
                     if (chmod($this->up_dir, 0777)) {
                         if (!empty($this->up_files)) {
                             foreach ($this->up_files as $up_file) {
                                 if (is_uploaded_file($up_file['tmp_name'])) {
                                     $file_name = $up_file['name'];
                                     if ($this->up_rename) {
                                         $file_ext = end(explode('.', $file_name));
                                         $file_rnd = substr(md5(uniqid()), mt_rand(0, 26), 6); 
                                         $file_name = date('ymdHis').'_'.$file_rnd.'.'.$file_ext;
                                     } 
                                     $file_name = $this->up_dir.'/'.$file_name;

                                     if (move_uploaded_file($up_file['tmp_name'], $file_name)) {
                                         $this->up_ret[] = str_replace(WEBSITE_DIRROOT, '', $file_name);
                                     } else {
                                         exit('文件上传失败!');
                                     }
                                 }
                             }
                         }
                     } else {
                         exit('未开启写入权限!');
                     }
                 } else {
                     exit('上传目录创建失败!');
                 }
             }

             public function GetUpload() {
                 return empty($this->up_ret) ? false : $this->up_ret;
             }

             function __destruct() {}
       }
?>
    asp:
<%
    Class MultiUpload

        REM PUBLIC-VARIANT

        Public  Form, IsFinished
        Private bVbCrlf, bSeparate, fPassed, formData, fileType, fileSize, folderPath, _
                fRename, fIMGOnly, itemCount, chunkSize, bTime, sErrors, sAuthor, sVersion
        Private itemStart(), itemLength(), dataStart(), dataLength(), itemName(), itemData(), extenArr(), httpArr()

        REM CLASS-INITIALIZE

        Private Sub Class_Initialize
            Call InitVariant
            Server.ScriptTimeOut = 1800
            Set Form = Server.CreateObject("Scripting.Dictionary")
            sAuthor = "51JS.COM-ZMM"
            sVersion = "MultiUpload Class 3.0"
        End Sub

        REM CLASS-ATTRIBUTES

        Public Property Let AllowType(byVal sType)
            Dim regEx
            Set regEx = New RegExp
            regEx.Pattern = "^(\w+\|)*\w+$"
            regEx.Global = False
            regEx.IgnoreCase = True
            If regEx.Test(sType) Then fileType = "|" & Ucase(sType) & "|"
            Set regEx = Nothing
        End Property
     
        Public Property Let MaxSize(byVal sSize)
            If IsNumeric(sSize) Then fileSize = CDbl(FormatNumber(CCur(sSize), 2))
        End Property

        Public Property Let SaveFolder(byVal sFolder)
            folderPath = sFolder
        End Property

        Public Property Let CommonPassed(byVal bCheck)
            fPassed = bCheck
        End Property

        Public Property Let FileRenamed(byVal bRename)
            fRename = bRename
        End Property

        Public Property Let FileIsAllImg(byVal bOnly)
            fIMGOnly = bOnly
        End Property

        Public Property Get SaveFolder
            SaveFolder = folderPath
        End Property

        Public Property Get FileRenamed
            FileRenamed = fRename
        End Property

        Public Property Get FileIsAllImg
            FileIsAllImg = fIMGOnly
        End Property

        Public Property Get ErrMessage
            ErrMessage = sErrors
        End Property
 
        Public Property Get ClsAuthor
            ClsAuthor = sAuthor
        End Property

        Public Property Get ClsVersion
            ClsVersion = sVersion
        End Property

        REM CLASS-METHODS

        Private Function InitVariant
            IsFinished = False
            bVbCrlf = StrToByte(vbCrlf & vbCrlf)
            bSeparate = StrToByte(String(29, "-"))
            fPassed = False
            fileType = "*"
            fileSize = "*"
            fRename = True
            fIMGOnly = True
            itemCount = 0
            chunkSize = 1024 * 128
            bTime = Now
            sErrors = ""
        End Function
 
        Public Function GetUploadData
            Dim curRead : curRead = 0
            Dim dataLen : dataLen = Request.TotalBytes
            Dim appName : appName = "PROGRESS" & IPToNum(GetClientIPAddr)
            Dim streamTmp 
            Set streamTmp = Server.CreateObject("ADODB.Stream")
            streamTmp.Type = 1
            streamTmp.Open        
            Do While curRead < dataLen
               Dim partLen : partLen = chunkSize
               If partLen + curRead > dataLen Then partLen = dataLen - curRead
               streamTmp.Write Request.BinaryRead(partLen)
               curRead = curRead + partLen               
               LetProgress appName, Array(curRead, dataLen, DateDiff("s", bTime, Now), folderPath) 
            Loop
            streamTmp.Position = 0
            formData = streamTmp.Read(dataLen)        
            streamTmp.Close
            Set streamTmp = Nothing
            Call ItemPosition
        End Function

        Private Function LetProgress(byVal sName, byVal vArr)
            Application.Value(sName) = Join(vArr, "|")
        End Function 

        Private Function DelProgress 
            Application.Contents.Remove("PROGRESS" & IPToNum(GetClientIPAddr))
        End Function

        Private Function ItemPosition
            Dim iStart, iLength : iStart = 1        
            Do Until InStrB(iStart, formData, bSeparate) = 0
               iStart = InStrB(iStart, formData, bSeparate) + LenB(bSeparate) + 14
               iLength = InStrB(iStart, formData, bSeparate) - iStart - 2
               If Abs(iStart + 2 - LenB(formData)) > 2 Then
                  ReDim Preserve itemStart(itemCount)
                  ReDim Preserve itemLength(itemCount)
                  itemStart(itemCount) = iStart
                  itemLength(itemCount) = iLength
                  itemCount = itemCount + 1
               End If
            Loop
            Call FillItemValue
        End Function

        Private Function FillItemValue
            Dim dataPart, bInfor
            Dim iStart : iStart = 1
            Dim iCount : iCount = 0
            Dim iCheck : iCheck = StrToByte("filename")
            For i = 0 To itemCount - 1
                ReDim Preserve itemName(iCount)
                ReDim Preserve itemData(iCount)
                ReDim Preserve extenArr(iCount)
                ReDim Preserve httpArr(iCount)
                ReDim Preserve dataStart(iCount)
                ReDim Preserve dataLength(iCount)
                dataPart = MidB(formData, itemStart(i), itemLength(i))
                iStart = InStrB(1, dataPart, ChrB(34)) + 1
                iLength = InStrB(iStart, dataPart, ChrB(34)) - iStart
                itemName(iCount) = GetItemName(MidB(dataPart, iStart, iLength))
                iStart = InStrB(1, dataPart, bVBCrlf) + 4
                iLength = LenB(dataPart) - iStart + 1
                If InStrB(1, dataPart, iCheck) > 0 Then
                   bInfor = MidB(dataPart, 1, iStart - 5)
                   extenArr(iCount) = FileExtenName(bInfor)
                   httpArr(iCount) = GetHttpContent(bInfor)
                   If IsNothing(extenArr(iCount)) Then
                      itemData(iCount) = ""
                      dataStart(iCount) = ""
                      dataLength(iCount) = ""                      
                   Else
                      If Mid(folderPath, Len(folderPath) - 1) = "/" Then
                         If fRename Then
                            itemData(iCount) = folderPath & GetRandomName(6) & extenArr(iCount)
                         Else
                            itemData(iCount) = folderPath & GetClientName(bInfor) & extenArr(iCount)
                         End If
                      Else
                         If fRename Then
                            itemData(iCount) = folderPath & "/" & GetRandomName(6) & extenArr(iCount) 
                         Else
                            itemData(iCount) = folderPath & "/" & GetClientName(bInfor) & extenArr(iCount)
                         End If
                      End If
                      dataStart(iCount) = itemStart(i) + iStart - 2
                      dataLength(iCount) = iLength
                   End If
                Else
                   extenArr(iCount) = ""
                   httpArr(iCount) = ""
                   itemData(iCount) = ByteToStr(MidB(dataPart, iStart, iLength))
                   dataStart(iCount) = ""
                   dataLength(iCount) = ""
                End If
                iCount = iCount + 1
            Next
            Call ItemToColl
        End Function

        Private Function GetItemName(byVal bName)
            GetItemName = ByteToStr(bName)
        End Function

        Private Function ItemToColl
            For i = 0 To itemCount - 1
                If Not Form.Exists(itemName(i)) Then
                   Form.Add itemName(i), itemData(i)
                End If
            Next         
        End Function

        Private Function FileExtenName(byVal bInfor)
            Dim pContent, regEx
            pContent = GetClientPath(bInfor)
            If IsNothing(pContent) Then
               FileExtenName = ""
            Else
               Set regEx = New RegExp
               regEx.Pattern = "^.+(\.[^\.]+)$"
               regEx.Global = False
               regEx.IgnoreCase = True
               FileExtenName = regEx.Replace(pContent, "$1")
               Set regEx = Nothing                
            End If      
        End Function

        Private Function GetHttpContent(byVal bInfor)
            Dim sInfor, regEx
            sInfor = ByteToStr(bInfor)
            Set regEx = New RegExp
            regEx.Pattern = "^[\S\s]+Content-Type:([\S\s]+)$"
            regEx.Global = False
            regEx.IgnoreCase = True
            GetHttpContent = Trim(regEx.Replace(sInfor, "$1"))
            Set regEx = Nothing
        End Function

        Private Function GetRandomName(byVal sLen)
            Dim regEx, sTemp, arrFields, n : n = 0
            Set regEx = New RegExp
            regEx.Pattern = "[^\d]+"
            regEx.Global = True
            regEx.IgnoreCase = True
            sTemp = regEx.Replace(Now, "") & "-"
            Set regEx = Nothing         
            arrFields = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", _ 
                              "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", _ 
                              "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", _
                              "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", _
                              "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", _
                              "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", _
                              "Y", "Z")
            Randomize
            Do While n < sLen
               sTemp = sTemp & CStr(arrFields(61 * Rnd))
               n = n + 1
            Loop
            GetRandomName = sTemp
        End Function

        Private Function GetClientName(byVal bInfor)
            Dim pContent, regEx
            pContent = GetClientPath(bInfor)
            If IsNothing(pContent) Then
               GetClientName = ""
            Else
               Set regEx = New RegExp
               regEx.Pattern = "^.*\\([^\.]*)[^\\]+$"
               regEx.Global = False
               regEx.IgnoreCase = True
               GetClientName = regEx.Replace(pContent, "$1")
               Set regEx = Nothing                
            End If  
        End Function

        Private Function GetClientPath(byVal bInfor)
            Dim sInfor, pStart, pLength, pContent
            sInfor = ByteToStr(bInfor)
            pStart = InStr(1, sInfor, "filename=" & Chr(34)) + 10
            pLength = InStr(pStart, sInfor, Chr(34)) - pStart
            pContent = Mid(sInfor, pStart, pLength)
            GetClientPath = pContent            
        End Function

        Public Function SaveUploadFile
            Dim isValidate
            Dim filePath, oStreamGet, oStreamPut
            isValidate = fPassed And CheckFile 
            If isValidate Then
               For i = 0 To itemCount - 1
                   If Not IsNothing(dataStart(i)) And Not IsNothing(dataLength(i)) Then
                      If dataLength(i) = 0 Then
                         itemData(i) = "" 
                      Else
                         filePath = Server.MapPath(itemData(i))
                         If CreateFolder("|", ParentFolder(filePath)) Then                     
                            Set oStreamGet = Server.CreateObject("ADODB.Stream")
                            oStreamGet.Type = 1
                            oStreamGet.Mode = 3
                            oStreamGet.Open
                            oStreamGet.Write formData
                            oStreamGet.Position = dataStart(i)
                            Set oStreamPut = Server.CreateObject("ADODB.Stream")
                            oStreamPut.Type = 1
                            oStreamPut.Mode = 3
                            oStreamPut.Open
                            oStreamPut.Write oStreamGet.Read(dataLength(i))
                            oStreamPut.SaveToFile filePath, 2
                            oStreamGet.Close
                            Set oStreamGet = Nothing
                            oStreamPut.Close
                            Set oStreamPut = Nothing
                         End If  
                      End If                   
                   End If
               Next
               IsFinished = True
            Else               
               IsFinished = False
            End If
        End Function

        Private Function CheckFile
            Dim oBoolean : oBoolean = True
            CheckFile = oBoolean And CheckType And CheckSize
        End Function

        Private Function CheckType
            Dim oBoolean : oBoolean = True
            If fileType = "*" Then
               oBoolean = oBoolean And True
            Else
               For i = 0 To itemCount - 1
                   If Not IsNothing(extenArr(i)) Then
                      If InStr(1, fileType, "|" & Ucase(Mid(extenArr(i), 2)) & "|") > 0 Then
                         If fIMGOnly Then
                            Dim sAllow : sAllow = "|GIF|PJPEG|X-PNG|BMP|"
                            Dim aCheck : aCheck = Split(UCase(httpArr(i)), "/")
                            Dim iCheck : iCheck = "|" & aCheck(Ubound(aCheck)) & "|"
                            If InStr(1, sAllow, iCheck, 1) > 0 Then
                               oBoolean = oBoolean And True
                            Else
                               sErrors = sErrors & "表单 [ " & itemName(i) & " ] 的文件格式错误!\n" & _
                                                   "支持的格式为:" & Replace(Mid(fileType, 2, Len(fileType) - 1), "|", " ") & "\n\n"
                               oBoolean = oBoolean And False   
                            End If
                         Else
                            oBoolean = oBoolean And True
                         End If
                      Else
                         sErrors = sErrors & "表单 [ " & itemName(i) & " ] 的文件格式错误!\n" & _
                                             "支持的格式为:" & Replace(Mid(fileType, 2, Len(fileType) - 1), "|", " ") & "\n\n"
                         oBoolean = oBoolean And False     
                      End If
                   End If 
               Next
            End If
            CheckType = oBoolean
        End Function

        Private Function CheckSize
            Dim oBoolean : oBoolean = True
            If fileSize = "*" Then
               oBoolean = oBoolean And True
            Else
               For i = 0 To itemCount - 1
                   If Not IsNothing(dataLength(i)) Then
                      Dim tmpSize : tmpSize = CDbl(FormatNumber(CCur(dataLength(i)) / 1024, 2))
                      If tmpSize <= fileSize Then
                         oBoolean = oBoolean And True
                      Else
                         sErrors = sErrors & "表单 [ " & itemName(i) & " ] 的文件大小 (" & tmpSize & " KB) 超出范围!\n" & _
                                             "支持大小范围:<= " & fileSize & " KB\n\n"
                         oBoolean = oBoolean And False     
                      End If
                   End If                    
               Next
            End If
            CheckSize = oBoolean
        End Function

        Private Function CreateFolder(byVal sLine, byVal sPath)
            Dim oFso
            Set oFso = Server.CreateObject("Scripting.FileSystemObject")
            If Not oFso.FolderExists(sPath) Then
               Dim regEx
               Set regEx = New RegExp
               regEx.Pattern = "^(.*)\\([^\\]*)$"
               regEx.Global = False
               regEx.IgnoreCase = True   
               sLine = sLine & regEx.Replace(sPath, "$2") & "|"
               sPath = regEx.Replace(sPath, "$1")     
               If CreateFolder(sLine, sPath) Then CreateFolder = True 
               Set regEx = Nothing
            Else
               If sLine = "|" Then
                  CreateFolder = True
               Else
                  Dim sTemp : sTemp = Mid(sLine, 2, Len(sLine) - 2)
                  If InStrRev(sTemp, "|") = 0 Then
                     sLine = "|"
                     sPath = sPath & "\" & sTemp             
                  Else
                     Dim Folder : Folder = Mid(sTemp, InStrRev(sTemp, "|") + 1)
                     sLine = "|" & Mid(sTemp, 1, InStrRev(sTemp, "|") - 1) & "|"
                     sPath = sPath & "\" & Folder
                  End If
                  oFso.CreateFolder sPath
                  If CreateFolder(sLine, sPath) Then CreateFolder = True             
               End if
            End If
            Set oFso = Nothing  
        End Function

        Private Function ParentFolder(byVal sPath)
            Dim regEx
            Set regEx = New RegExp
            regEx.Pattern = "^(.*)\\[^\\]*$"
            regEx.Global = True
            regEx.IgnoreCase = True
            ParentFolder = regEx.Replace(sPath, "$1")
            Set regEx = Nothing             
        End Function

        Private Function IsNothing(byVal sVar)
            IsNothing = CBool(sVar = Empty)
        End Function

        Private Function StrPadLeft(byVal sText, byVal sLen, byVal sChar)
            Dim sTemp : sTemp = sText
            Do While Len(sTemp) < sLen : sTemp = sChar & sTemp : Loop
            StrPadLeft = sTemp
        End Function

        Private Function StrToByte(byVal sText) 
            For i = 1 To Len(sText)     
                StrToByte = StrToByte & ChrB(Asc(Mid(sText, i, 1)))   
            Next
        End Function

        Private Function ByteToStr(byVal sByte)
            Dim oStream
            Set oStream = Server.CreateObject("ADODB.Stream")
            oStream.Type = 2
            oStream.Mode = 3
            oStream.Open
            oStream.WriteText sByte
            oStream.Position = 0
            oStream.CharSet = "gb2312"
            oStream.Position = 2
            ByteToStr = oStream.ReadText
            oStream.Close 
            Set oStream = Nothing         
        End Function

        Private Function GetClientIPAddr
            If IsNothing(GetServerVar("HTTP_X_FORWARDED_FOR")) Then
               GetClientIPAddr = GetServerVar("REMOTE_ADDR")
            Else
               GetClientIPAddr = GetServerVar("HTTP_X_FORWARDED_FOR")
            End If
        End Function

        Private Function GetServerVar(byVal sText)
            GetServerVar = Request.ServerVariables(sText)
        End Function

        Private Function IPToNum(byVal sIp) 
            Dim sIp_1, sIp_2, sIp_3, sIp_4
            If IsNumeric(Left(sIp, 2)) Then
               sIp_1 = Left(sIp, InStr(sIp, ".") - 1)
               sIp = Mid(sIp, InStr(sIp, ".") + 1)
               sIp_2 = Left(sIp, InStr(sIp, ".") - 1)
               sIp = Mid(sIp, InStr(sIp, ".") + 1)
               sIp_3 = Left(sIp, InStr(sIp, ".") - 1)
               sIp_4 = Mid(sIp, InStr(sIp, ".") + 1)
            End If
            IPToNum = CInt(sIp_1) * 256 * 256 * 256 + CInt(sIp_2) * 256 * 256 + CInt(sIp_3) * 256 + CInt(sIp_4) - 1
        End Function

        REM CLASS-TERMINATE

        Private Sub Class_Terminate
            Call DelProgress
            Form.RemoveAll
            Set Form = Nothing
        End Sub 
      
    End Class
%>
posted on 2011-03-20 18:50  web freer  阅读(849)  评论(0编辑  收藏  举报