php中关于普通表单多文件上传的处理方法

  然而有些情况只需要传递几个文件,而且文件体积并不太大,这种情况下使用组件则有点牛刀杀鸡的感觉,通过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: [email protected]

  * 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

  %>