【问题标题】:How do I reference an uploaded file in a server-side Classic ASP page?如何在服务器端经典 ASP 页面中引用上传的文件?
【发布时间】:2019-03-19 21:54:39
【问题描述】:

我正在尝试通过 Ajax 将文件上传到用经典 ASP 编写的服务器端脚本。

这是相关的 HTML 和 JavaScript 代码:

<input type="file" id="fileInput" />

function saveToServer(file) {
    const fd = new FormData();
    fd.append('image', file);
    const xhr = new XMLHttpRequest();
    xhr.open('POST', 'http://localhost/post.asp', true);
    xhr.onload = () => {
        if (xhr.status === 200) {
            // Do stuff with response
        }
    };
    xhr.send(fd);
}

const fileInput = document.getElementById("fileInput");

fileInput.addEventListener("change", () => {
    const file = fileInput.files[0];
    if (/^image\//.test(file.type)) {
        saveToServer(file);
    } else {
        console.warn('You can only upload images.');
    }
});

我的问题是:如何在我的经典 ASP 页面 (post.asp) 中获取对上传文件的引用?

在 PHP 中有一个可用的全局变量 $_FILES,其中包含如下内容:

Array
(
  [image] => Array
  (
    [name] => cat.png
    [type] => image/png
    [tmp_name] => /tmp/phpOjXMW3
    [error] => 0
    [size] => 10603
  )
)

Classic ASP 中是否有类似的东西?


这是帖子页面:

Set upl = New FileUploader 
upl.Upload()
If upl.Files.Count = 1 Then
  For Each File In upl.Files.Items
    If File.FileSize < 100000 Then
      File.FileName =  upl.Form ("id") & ".jpg"
      File.SaveToDisk Server.MapPath("/Images")
  next
end if

这是帖子页面顶部的包含:

Class FileUploader
    Public  Files
    Private mcolFormElem

    Private Sub Class_Initialize()
        Set Files = Server.CreateObject("Scripting.Dictionary")
        Set mcolFormElem = Server.CreateObject("Scripting.Dictionary")
    End Sub

    Private Sub Class_Terminate()
        If IsObject(Files) Then
            Files.RemoveAll()
            Set Files = Nothing
        End If
        If IsObject(mcolFormElem) Then
            mcolFormElem.RemoveAll()
            Set mcolFormElem = Nothing
        End If
    End Sub

    Public Property Get Form(sIndex)
        Form = ""
        If mcolFormElem.Exists(LCase(sIndex)) Then Form = mcolFormElem.Item(LCase(sIndex))
    End Property

    Public Default Sub Upload()
        Dim biData, sInputName
        Dim nPosBegin, nPosEnd, nPos, vDataBounds, nDataBoundPos
        Dim nPosFile, nPosBound
    'response.Flush

        biData = Request.BinaryRead(Request.TotalBytes)
        nPosBegin = 1
        nPosEnd = InstrB(nPosBegin, biData, CByteString(Chr(13)))

        If (nPosEnd-nPosBegin) <= 0 Then Exit Sub

        vDataBounds = MidB(biData, nPosBegin, nPosEnd-nPosBegin)
        nDataBoundPos = InstrB(1, biData, vDataBounds)

        Do Until nDataBoundPos = InstrB(biData, vDataBounds & CByteString("--"))

            nPos = InstrB(nDataBoundPos, biData, CByteString("Content-Disposition"))
            nPos = InstrB(nPos, biData, CByteString("name="))
            nPosBegin = nPos + 6
            nPosEnd = InstrB(nPosBegin, biData, CByteString(Chr(34)))
            sInputName = CWideString(MidB(biData, nPosBegin, nPosEnd-nPosBegin))
            nPosFile = InstrB(nDataBoundPos, biData, CByteString("filename="))
            nPosBound = InstrB(nPosEnd, biData, vDataBounds)

            If nPosFile <> 0 And  nPosFile < nPosBound Then
                Dim oUploadFile, sFileName
                Set oUploadFile = New UploadedFile

                oUploadFile.FormElement = MidB(biData, nPos, 5)


                nPosBegin = nPosFile + 10
                nPosEnd =  InstrB(nPosBegin, biData, CByteString(Chr(34)))
                sFileName = CWideString(MidB(biData, nPosBegin, nPosEnd-nPosBegin))
                oUploadFile.FileName = Right(sFileName, Len(sFileName)-InStrRev(sFileName, "\"))

                nPos = InstrB(nPosEnd, biData, CByteString("Content-Type:"))
                nPosBegin = nPos + 14
                nPosEnd = InstrB(nPosBegin, biData, CByteString(Chr(13)))

                oUploadFile.ContentType = CWideString(MidB(biData, nPosBegin, nPosEnd-nPosBegin))

                nPosBegin = nPosEnd+4
                nPosEnd = InstrB(nPosBegin, biData, vDataBounds) - 2
                oUploadFile.FileData = MidB(biData, nPosBegin, nPosEnd-nPosBegin)

                If oUploadFile.FileSize > 0 Then Files.Add LCase(sInputName), oUploadFile
            Else
                nPos = InstrB(nPos, biData, CByteString(Chr(13)))
                nPosBegin = nPos + 4
                nPosEnd = InstrB(nPosBegin, biData, vDataBounds) - 2
                If Not mcolFormElem.Exists(LCase(sInputName)) Then mcolFormElem.Add LCase(sInputName), CWideString(MidB(biData, nPosBegin, nPosEnd-nPosBegin))
            End If

            nDataBoundPos = InstrB(nDataBoundPos + LenB(vDataBounds), biData, vDataBounds)
        Loop
    End Sub

    'String to byte string conversion
    Private Function CByteString(sString)
        Dim nIndex
        For nIndex = 1 to Len(sString)
           CByteString = CByteString & ChrB(AscB(Mid(sString,nIndex,1)))
        Next
    End Function

    'Byte string to string conversion
    Private Function CWideString(bsString)
        Dim nIndex
        CWideString =""
        For nIndex = 1 to LenB(bsString)
           CWideString = CWideString & Chr(AscB(MidB(bsString,nIndex,1))) 
        Next
    End Function
End Class

Class UploadedFile
    Public ContentType
    Public FileName
    Public FileData
    Public FormElement

    Public Property Get FileSize()
        FileSize = LenB(FileData)
    End Property

    Public Sub SaveToDisk(sPath)
        Dim oFS, oFile
        Dim nIndex

        If sPath = "" Or FileName = "" Then Exit Sub
        If Mid(sPath, Len(sPath)) <> "\" Then sPath = sPath & "\"

        Set oFS = Server.CreateObject("Scripting.FileSystemObject")
        If Not oFS.FolderExists(sPath) Then Exit Sub

        Set oFile = oFS.CreateTextFile(sPath & FileName, True)

        For nIndex = 1 to LenB(FileData)
            oFile.Write Chr(AscB(MidB(FileData,nIndex,1)))
        Next

        oFile.Close
    End Sub

    Public Sub SaveToDatabase(ByRef oField)
        If LenB(FileData) = 0 Then Exit Sub

        If IsObject(oField) Then
            oField.AppendChunk FileData
        End If
    End Sub

End Class

【问题讨论】:

  • 你的 post.asp 代码是什么?您是否使用第三方组件上传?
  • 已回复您的回复。谢谢!
  • @AspClassic-Guy 的答案不是用于发布回复,而是edit 问题并添加其他内容。建议在发帖前使用tour 并通读How to Ask
  • 有来自upl.Files 集合的对象File,我不确定问题是什么?

标签: javascript ajax asp-classic


【解决方案1】:

这个问题没有多大意义……

我的问题是:

如何在我的经典 ASP 页面 (post.asp) 中获取对上传文件的引用?

从您发布的代码中可以清楚地看出,您正在使用自定义类来支持上传FileUploader,它会为您解析二进制文件并构建代表上传文件的对象集合(UploadedFile 类)。

在您发布的代码中,您正在For Each 循环中访问UploadedFile 对象;

Set upl = New FileUploader 
upl.Upload()
If upl.Files.Count = 1 Then
  For Each File In upl.Files.Items
    If File.FileSize < 100000 Then
      File.FileName =  upl.Form ("id") & ".jpg"
      File.SaveToDisk Server.MapPath("/Images")
    End If
  Next
End If

更正了End IfFor Each 结束之前丢失的错字。

在该示例中,您的 File 对象是 UploadedFile 类对象,其中包含在解析二进制文件期间由 FileUploader 填充的文件属性。

【讨论】:

  • 我感觉他们想要在保存到磁盘之前检查文件。就像 PHP 的$_FILES 允许您在重命名和移动之前查看临时上传文件夹中文件的属性。
  • @Adam 我没有太多使用 PHP,但仍然不明白你的意思,据我所知,$_FILES 只是当时他们不使用的解析文件的集合'不存在于内存中(除非 PHP 有一些我不知道的奇怪配置).
  • 是的,我希望能够在控制台中看到信息。
  • @AspClassic-Guy 什么控制台?你是指客户端浏览器开发工具吗?
  • 我的意思是,我希望经典的 ASP 脚本返回上传文件的属性,以便在 Ajax 成功回调(在客户端)中,我可以将这些属性输出到控制台。
【解决方案2】:

上传文件后,您可以使用FileSystemObject 检查文件是否存在并通过GetFile 方法检索其属性。使用函数来节省空间并返回属性字典,使它们更易于引用:

function getFileInfo(ByVal fileLocation)

    ' Use MapPath to convert to an absolute path

    fileLocation = Server.MapPath(fileLocation)

    ' Set the file system and dictionary objects using reserved words

    set fileSystem = Server.CreateObject("Scripting.FileSystemObject")
    Set dictionary = Server.CreateObject("Scripting.Dictionary")

    ' Check that the file exists

    if fileSystem.FileExists(fileLocation) then

        ' Use GetFile to retrieve the files properties

        set file = fileSystem.GetFile(fileLocation)

        ' Add each property to the dictionary object

        dictionary.add "FileFound",true
        dictionary.add "Attributes",file.Attributes
        dictionary.add "DateCreated",file.DateCreated
        dictionary.add "DateLastAccessed",file.DateLastAccessed
        dictionary.add "DateLastModified",file.DateLastModified
        dictionary.add "Drive",file.Drive
        dictionary.add "Name",file.Name
        dictionary.add "ParentFolder",file.ParentFolder
        dictionary.add "Path",file.Path
        dictionary.add "ShortName",file.ShortName
        dictionary.add "ShortPath",file.ShortPath
        dictionary.add "Size",file.Size
        dictionary.add "Type",file.Type

        ' Attributes translations:
        ' 0 = Normal file
        ' 1 = Read-only file
        ' 2 = Hidden file
        ' 4 = System file
        ' 16 = Folder or directory
        ' 32 = File has changed since last backup
        ' 1024 = Link or shortcut
        ' 2048 = Compressed file

    else

        ' File not found

        dictionary.add "FileFound",false

    end if

    ' Return the dictionary object

    set getFileInfo = dictionary

    ' Set all objects to nothing

    set fileSystem = nothing
    set dictionary = nothing
    set file = nothing

end function

检查文件是否已上传并检索其属性:

Dim fileInfo : Set fileInfo = getFileInfo("../../uploads/cat.jpg")  

    ' getFileInfo("/Images/" & upl.Form ("id") & ".jpg") 

    if fileInfo.item("FileFound") then

        ' Output all the file properties

        for each item in fileInfo
            response.write "<b>" & item & "</b>: " & fileInfo.item(item) & "<br>"
        next

        ' Output a specific file property

        response.write "<b>The file size is</b>: " & fileInfo.item("Size") & " bytes<br>"
        response.write "<b>The file type is</b>: " & fileInfo.item("Type") & "<br>"

    else

        response.write "File not found"

    end if

Set fileInfo = nothing

示例输出:

FileFound:真属性:32
创建日期:20/03/2019 12:40:09
DateLastAccessed:20/03/2019 12:40:09
DateLastModified:20/03/2019 12:40:09
驱动器: C:
名称: cat.jpg
ParentFolder: C:\inetpub\wwwroot\uploads
路径 strong>:C:\inetpub\wwwroot\uploads\cat.jpg
ShortName:cat.jpg
ShortPath:C:\inetpub\wwwroot\uploads \cat.jpg
大小:992514
类型:JPEG图像
文件大小:992514字节
文件类型为:JPEG图片


编辑:继 Lankymart 的评论之后,您可以使用 upl.Files 对象在将文件保存到磁盘之前执行一些初步检查:

function randomFileName()

    ' Randomize() generates quite a small seed number, so you will generate duplicate
    ' filenames if you upload enough images. To prevent this, prefix a random number
    ' with a unix timestamp.

    Dim uts : uts = DateDiff("s","1970-01-01 00:00:00",Now())

    Randomize()

    ' filename format: [unix timestamp][random 7 digit number]

    randomFileName = cStr(uts & Int((9999999-1000000+1)*Rnd+1000000))

end function

function validExtension(ByVal allowed, ByVal fileName)

    Dim extRegexp : Set extRegexp = New RegExp

    extRegexp.Pattern = "^.*\.(" & lCase(allowed) & ")$"
    validExtension = extRegexp.Test(lCase(fileName))

end function

if Request.TotalBytes > 0 then

    Const max_upload_size = 100000 ' bytes
    Const allowed_extensions = "jpg|jpeg|png"
    Const upload_folder = "/Images/"

    Dim upload_successful : upload_successful = false
    Dim upload_message : upload_message = ""
    Dim rndFileName, fileExt, fileSplit

    Dim upl : Set upl = New FileUploader 
    upl.Upload()

    If upl.Files.Count = 1 Then

        For Each File In upl.Files.Items

            file.ContentType = lCase(file.ContentType)
            File.FileName = trim(File.FileName)

            if NOT (file.ContentType = "image/jpeg" _
            OR file.ContentType = "image/jpg" _
            OR file.ContentType = "image/png") then

                upload_message = "Invalid file type"

            elseif NOT validExtension(allowed_extensions,File.FileName) then

                upload_message = "Invalid file type"

            elseif File.FileSize > max_upload_size then

                upload_message = "File too big"

            else

                ' Extract the file extension

                fileSplit = split(File.FileName,".")
                fileExt = lCase(fileSplit(uBound(fileSplit)))

                ' Generate a random file name

                rndFileName = randomFileName() & "." & fileExt

                ' Everything checks out, save to disk

                File.FileName = rndFileName
                File.SaveToDisk Server.MapPath(upload_folder)

                upload_message = "Upload successful"

                upload_successful = true

            end if

        next

    else

        upload_message = "Maximum upload count exceeded"

    end if

    Set upl = nothing

    ' Return a JSON string      

    Response.ContentType = "application/json"

    response.write _
    "{""uploaded"":" & lCase(upload_successful) & "," &_
    """message"":""" & upload_message & """," &_
    """file"":""" & upload_folder & rndFileName & """}"

end if

【讨论】:

  • 他们已经拥有UploadedFile 对象,该对象为他们提供了在上传期间从二进制文件中解析的所有值。 FileUploader 中的解析会创建一个 Scripting.Dictionary 以包含每个 UploadedFile,就像 Classic ASP 的大多数自定义上传器类一样。
  • 如果你在 post.asp 中使用它并上传
  • @AspClassic-Guy 是的,文件大小检查接受 100000 字节或更少。文件扩展名是从原始文件名中提取的,mime 类型是从图像标题中提取和分析的。
  • @Lankymart 发布到 post.asp 页面的文件是常规形式的帖子。这是否:upl.Form ("id") 必须在 post.asp 页面上才能让上传者工作?
  • @AspClassic-Guy 这就是您在原始代码中设置它的方式。您可以在您的 post.asp 页面中生成一个随机文件名。我已经用代码更新了一个例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-18
相关资源
最近更新 更多