【问题标题】:ColdFusion handling of HTML5 <input type="file" multiple="multiple" />HTML5 <input type="file" multiple="multiple" /> 的 ColdFusion 处理
【发布时间】:2011-11-12 09:41:51
【问题描述】:

我正在尝试实现一个 HTML5 输入字段,让用户选择要上传的多个文件。我的表单中有以下内容:

<form method="post" enctype="multipart/form-data" action="index.cfm">
    <input type="file" name="Images" id="Images" multiple="multiple" accept="image/jpeg, image/gif, image/png, application/zip" />
    ...

我可以在浏览器中选择多个文件,然后单击上传,但我不确定如何使用 ColdFusion 处理表单发布。我认为以下方法会起作用,但这只会上传我选择的最后一个文件:

<cfloop list="#attributes.Images#" index="Image">
    <cffile
        destination = "#ExpandPath(Trim(request.TempFolder))#"
        filefield = "Images"
        action = "upload"
        nameconflict = "MakeUnique"
        result = "UploadedTempFile"
    >
    <cfoutput>#UploadedTempFile.serverFile#<br /></cfoutput>
</cfloop>

有人可以向我解释如何遍历通过我的一个表单字段提交的所有文件,以便我可以单独处理这些文件吗?

【问题讨论】:

  • 您是否尝试过使用&lt;cffile action="uploadAll" /&gt;?它只是 CF9,我自己没有测试过,但这可能会奏效。在 CF8 中,我只得到一个图像字段。
  • 该死,这正是我所需要的,但我现在卡在 CF8 上。有什么建议吗?
  • 不使用 HTML 5 表单:/,我在 CF8 中将 Uploadify 用于这些类型的上传器,或者在 CF9 中使用 cffileupload 标记。老实说,我不确定我提供的解决方案是否可行......
  • 再看一遍,似乎 uploadAll 是为了处理同名的多个输入元素而创建的。我真的只是想处理一个具有“多个”属性的输入元素。我希望它只会创建一个文件数组,然后我可以单独循环遍历这些文件,就像循环遍历多个同名文本输入字段一样。
  • 我必须对其进行测试,因为当我在 CF8 中使用您的示例表单时,它显示了多个名为“图像”的表单元素,而不是单个表单元素。我会看看我是否可以让uploadall 在 CF9 中工作并回复你。

标签: html file-upload file-io coldfusion


【解决方案1】:

更新:从 ColdFusion 9 开始,这是真的。这已在 ColdFusion 10 中得到纠正。

结束我们的评论对话:

这对于默认的 ColdFusion 行为是不可能的。 cffile 不支持从单个 file 元素处理多个文件上传。我认为有可能回退到 JAVA 来执行此操作,但我不知道如何做到这一点。

我希望cffile action="uploadall" 获取所有 HTML5 多文件元素。需要将其归档为 CF10 的 ER :)。

【讨论】:

  • 是的,在CF10的cffile action=uploadall中支持
【解决方案2】:

在搜索了许多博客文章、偶然发现并阅读了 Adob​​e 的文档后,似乎一致认为 CF10 不支持“多个”文件上传支持(除非您使用的是 flash 表单)。问题是,cffile 标记的“uploadall”值可能会上传所有文件,但不会返回有关文件的结果数组。

这是我整合的一个函数,它利用了底层 Java 方法并在 ACF 10 中进行了测试。

<cffunction name="getUploadedFiles" access="public" returntype="struct"
    hint="Gets the uploaded files, grouped by the field name">
    <cfset var local = {
        files = {}, 
        types = "text/plain,text/csv,application/msexcel,application/vnd.ms-excel,application/octet-stream",
        tempFiles = form.getTempFiles(),
        idx = 0} />

    <cfscript>
        arrayEach(form.getPartsArray(), function (field) {
            var local = {fieldName = field.getName(), destinationFile = ""};

            // Make sure the field available in the form is also
            // available for the temporary files
            if (structKeyExists(tempFiles, fieldName)) {

                // Create the files of field array if it doesn't exist
                if (!structKeyExists(files, fieldName)) {
                    files[fieldName] = [];
                }

                // If only 1 file was uploaded, it won't be an array - so make it one
                if (!isArray(tempFiles[fieldName])) {
                    tempFiles[fieldName] = [tempFiles[fieldName]];
                }

                // Check that the form part is a file and within our list of valid types
                if (field.isFile() && listFindNoCase(types, field.getContentType())) {

                    // Compile details about the upload
                    arrayAppend(files[fieldName], {
                        file = tempFiles[fieldName][++idx],
                        filePart = field,
                        filename = field.getFileName(),
                        filepath = field.getFilePath(),
                        contentType = field.getContentType(),
                        tempFile = tempFiles[fieldName][idx].getPath()
                    });
                }
            }
        });
    </cfscript>

    <cfreturn local.files />
</cffunction>

与 cmets 一起,这只是循环所有表单部分,查找文件,并创建一个包含一些有用文件详细信息的数组(并根据我的应用程序要求按特定内容类型进行过滤)。

然后,我创建了 uploadFile 函数,该函数接受 fieldNamedestinationPath 参数。我根据传入的字段获取上传文件的数组,遍历文件以确保目标文件路径不存在(如果存在则使其唯一),然后使用 的内容写入目标文件从临时上传引用的 java.io.File 对象。

<cffunction name="uploadFile" access="public" returntype="array"
    hint="Uploads a file (or multiple files) from the form to the server">
    <cfargument name="fieldName" type="string" required="true" />
    <cfargument name="destinationPath" type="string" required="true" />

    <cfset var local = {files = [], filepaths = [], allFiles = getUploadedFiles()} />

    <cfif structKeyExists(local.allFiles, arguments.fieldName)>
        <cfset local.files = local.allFiles[arguments.fieldName] />
    </cfif>

    <cfloop array="#local.files#" index="local.file">
        <cfset local.file.destinationFile = arguments.destinationPath & local.file.fileName />

        <cfif fileExists(local.file.destinationFile)>
            <cfset local.file.destinationFile = listFirst(local.file.destinationFile, ".") & "_#getTickCount()#.csv" />
        </cfif>

        <cfset fileWrite(local.file.destinationFile, fileRead(local.file.file)) />
        <cfset arrayAppend(local.filePaths, local.file.destinationFile) />
    </cfloop>

    <cfset setActiveFileName(local.filePaths[arrayLen(local.filePaths)]) />

    <cfreturn local.filePaths />
</cffunction>

现在我可以完全控制所有上传的文件,并且可以处理需要的结果。

【讨论】:

    【解决方案3】:

    fileUploadAll()/&lt;cffile action="uploadAll"&gt; 允许您上传所有文件,也可以上传&lt;input type="file" multiple&gt; 的多个文件。

    虽然它总是处理请求的所有个文件,即它不区分不同的文件输入,您可能希望以不同的方式处理,例如通过 accept 参数设置不同的允许 MIME 类型,或将文件上传到每个输入的不同位置。

    因此,我在 Adobe ColdFusionLucee issue tracker 上创建了增强请求。

    基本思路是改变fileUpload()函数和&lt;cffile action="upload"&gt;在表单域​​有多个文件时自动返回一个数组,或者如果这导致兼容性问题,添加一个新参数multiple默认为false控制它。

    【讨论】:

    • 使用 cffile action="uploadAll" 对我有用,CF11:trycf.com/gist/5614a9693ef6cd712a151c5d1d350c12/…(我知道您在谈论常规上传,但是 ... uploadAll 是一个选项)。
    • 是的,&lt;cffile action="uploadAll"&gt; 在大多数情况下都有效,尽管它会上传请求的所有文件。如果表单中有多个 &lt;input type="file"&gt; 元素,则不能以不同的方式处理它们,例如将选定的文件上传到不同的地方。我已经更新了我的答案以澄清这一点。
    • 是的。没错,需要更精细的控制。
    猜你喜欢
    • 1970-01-01
    • 2015-10-10
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 2013-02-18
    • 1970-01-01
    • 2012-10-02
    • 1970-01-01
    相关资源
    最近更新 更多