PHP's handling of multiple file uploads for common forms

  • 2020-03-31 21:39:16
  • OfStack

However, there are cases where only a few files need to be passed, and the file size is not too large. Input type = "file" > The form can achieve the required function, the key is the processing of the background receiver.

PHP handles uploads conveniently, and the information is automatically processed by the server into the $_FILES array. Developers only need to use the built-in handler to do this. ASP developers are not so lucky, the official did not provide directly, the processing method requires developers to design their own, this is where the developers know IIS to enctype = "multipart/form - data" form handling, IIS the enctype = "multipart/form - data" form is submitted data is stored into the binary data, in binary format is returned to the developers, developers need through the analysis of the byte processing function to LenB, MidB access to upload content, Client sent the specific form data format, you can understand the HTTP RFC1867 protocol transmission format knowledge.

Here's how I handle multiple file uploads, both PHP and asp.

PHP: WEBSITE_DIRROOT PHP: WEBSITE_DIRROOT
 
<?php 
/* 
* class:  File upload 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 File domain name called empty, initialization failed! '); 
} 
} 

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(' I didn't find what I needed upload The file! '); 
} 
} 

$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(' Upload is not allowed '.$up_file['type'].' Format file! '); 

if ($up_file['size'] / 1024 > $this->up_max) { 
exit(' Upload greater than is not allowed  '.$this->up_max.'K  The file! '); 
} 
} 
} 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(' Upload is not allowed .'.$up_ext.' Format file! '); 

if ($up_file['size'] / 1024 > $this->up_max) { 
exit(' Upload greater than is not allowed  '.$this->up_max.'K  The file! '); 
} 
} 
} 

$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(' File upload failed! '); 
} 
} 
} 
} 
} else { 
exit(' Write permission not enabled! '); 
} 
} else { 
exit(' Upload directory creation failed! '); 
} 
} 

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 = "^[Ss]+Content-Type:([Ss]+)$" 
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 & " The form  [ " & itemName(i) & " ]  File format error! n" & _ 
" The supported format is: " & Replace(Mid(fileType, 2, Len(fileType) - 1), "|", " ") & "nn" 
oBoolean = oBoolean And False 
End If 
Else 
oBoolean = oBoolean And True 
End If 
Else 
sErrors = sErrors & " The form  [ " & itemName(i) & " ]  File format error! n" & _ 
" The supported format is: " & Replace(Mid(fileType, 2, Len(fileType) - 1), "|", " ") & "nn" 
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 & " The form  [ " & itemName(i) & " ]  File size  (" & tmpSize & " KB)  Out of range! n" & _ 
" Support size range: <= " & fileSize & " KBnn" 
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 
%> 


Related articles: