网页上传是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
- %>
复制代码
|