还记得和重新填充文件输入[复制]还记得和重新填充文件输入[复制](Remember and Repo

2019-05-08 22:49发布

这个问题已经在这里有一个答案:

  • 如何页删除文件时,设置文件输入值? [重复] 1个回答

注意:

下面的答案(S)反映传统的浏览器在2009年现在,你实际上可以通过JavaScript在2017年设定的文件输入元素的值的状态。

见这个问题的详细信息,以及演示了答案:
如何设置文件的输入值编程(即:当拖拽文件拖放)?

我有一个网站,允许用户将文件多次上传处理。 目前,我有一个单一的文件输入,但我希望能够记住用户的选择,并显示在屏幕上。

我想知道如何做的是用户选择文件后,我会记住他们的选择和重新显示在页面重新加载预先选定的文件的文件输入。 所有我需要知道的是如何记忆和重新填充文件输入。

我也开不使用文件输入(如果可能的话)的方法。

我使用JQuery

Answer 1:

好吧,你要“记住和重新填充文件输入 ”,“记住他们的选择和重新显示 在页面重新加载预先选定文件 的文件输入 ” ..
而在我以前的答案的评论你指出你不是真的开放的替代品:“对不起,但没有闪光灯和小程序,只是javscript和/或文件输入,可能拖放”。

我注意到在浏览(一段)重复的问题( 1 , 2 , 3等),几乎所有其他的答案是沿着线:“不,你不能,那将是一个安全问题”,然后任选通过简单的概念或代码示例,概述了安全风险。

然而,有人固执得像头骡子(不一定是坏事达到一定水平)可能会觉得这些问题的答案是:“没有,因为我这么说”,这的确是那么不同的东西:“不,此处的规范是DIS-允许它”。
所以这是我第三次和最后一次尝试回答你的问题(我引导你到浇水洞,我领你到河边,现在我推你到源,但我不能让你喝)。

编辑3:

你想做的事竟一下子中所述/“建议”什么RFC1867第3.4节:

VALUE属性可能与使用<INPUT TYPE=file>为默认文件名称标签。 这种使用可能是依赖于平台。 这可能是有用的,但是,在一个以上的交易,例如序列,以避免用户提示输入相同的文件名了一遍又一遍。

事实上,在HTML 4.01规范第17.4.1规定:

用户代理可以使用属性的值作为初始文件名的值。

(通过“用户代理”他们的意思是“浏览器”)。

由于JavaScript的既可以修改并提交表单(包括文件输入)的事实,人们可以使用CSS来隐藏表单/表单元素(如文件输入),仅在上述声明将有可能以静默上传从用户的计算机文件,而无需他的意图/知识。
这显然是极为重要的,这是不可能的,并且因此,(见上文)在第8安全注意事项 RFC1867规定:

一个用户代理不能发送用户没有明确要求发送的任何文件是很重要的。 因此,HTML解释代理商预计,以确认可能会被建议任何默认的文件名<INPUT TYPE=file VALUE="yyyy">

然而,唯一的浏览器(我知道的)有史以来实现这一功能是(一些旧版本的) 歌剧 :它接受一个<input type="file" value="C:\foo\bar.txt>或价值由JavaScript设定( elm_input_file.value='c:\\foo\\bar.txt';
当此文件的箱子是在不变的形式提交,歌剧会弹出一个安全窗口,通知有关地方要上传到什么位置(URL /网络服务器)是什么文件(S)的用户。

现在,人们可能会认为, 所有其他的浏览器分别对违反规范的,但是这将是错误的:因为该规范指出:“ may ”(它没有说“ must ‘)’..使用价值属性为初始文件名” 。
而且,如果浏览器不接受设置文件的输入值(也就是,具有价值仅仅是“只读”),那么浏览器也将不需要弹出这样一个“可怕”和“困难”的安全-pop后(可能甚至没有担任它的目的,如果用户不明白它(和/或在“条件”要始终单击“OK”))。

让我们快进到HTML 5的话..
这里所有的这种不确定性被清除了(但它仍然需要一些令人费解的):

4.10.7.1.18文件上传状态 ,我们可以在簿记细节如下:

  • 值IDL属性是模式的文件名。
    ...
  • 元素的值属性必须被省略。

因此,文件输入的值属性必须被省略,但它也运行在某种称为其描述在“文件名”“模式”的4.10.7.4常见的输入元素的API

值IDL属性允许脚本操作的输入元素的值。 该属性是在下列模式,其中定义其行为中的一种:

跳过这个“ 模式文件名 ”:

如果列表为空,然后在选定的文件列表中的第一个文件的文件名,如果有的话,或空字符串:在获取时,必须返回字符串“\ fakepath \ C”。 在设置时,如果新值是空字符串,它必须清空选中文件列表; 否则,它必须抛出一个异常InvalidStateError。

让我重复一遍:“它must抛出一个异常InvalidStateError”如果试图向一个文件的输入值设置为一个字符串,不是空的! (但可以通过设置它的值设置为空字符串清除输入字段。)

因此,目前并在可预见的未来HTML5(和在过去,除歌剧), 只有用户可以填充一个文件输入 (经由浏览器或操作系统提供的“文件选择”)。 一个不能(重新)填充输入文件到一个文件/目录的JavaScript或通过设置默认值。

获取文件名/文件路径

现在, 假设这不是不可能的(再)填充文件输入一个默认值,那么显然你需要的完整路径:目录+文件名(+扩展名)。

在过去,像(最显着的)IE6某些浏览器(最多IE8) 确实揭示的完整路径+文件名作为值:只是一个简单的alert( elm_input_file.value ); 等等。在JavaScript和浏览器也发送给接收服务器这个完整路径+文件名(+扩展名)的形式提交。
注意:一些浏览器也有“文件或文件名”属性(通常发送到服务器),但显然,这将不包括路径..

这是一个现实的安全/隐私风险:恶意网站(所有者/开发者)可以获取路径到用户的主目录(其中个人的东西,账户,饼干,注册表,历史,收藏夹的用户部分,台式机等是)位于已知常数位置时,典型的非高科技Windows的用户将上传他的文件: C:\Documents and Settings\[UserName]\My Documents\My Pictures\kinky_stuff\image.ext
我甚至没有谈,同时将数据(甚至通过https“加密”)的风险或该数据的“安全”存储!

因此,越来越多的其他浏览器已经开始遵循最古老的经过验证的安全措施之一:需要到了解的基础上共享信息。
而且绝大多数的网站并不需要知道文件的路径,所以他们只显示文件名(+扩展名)。

通过IE8发布时,微软决定跟随的竞争,并增加了URLAction选项,被称为“上传文件时包含本地目录路径”,它被设置为“禁用”为广大互联网区(和“启用”在受信任的区域),在默认情况下。

这种变化创造了一个小的破坏(主要是在环境“为IE优化”),其中各类两种自定义代码和专有的“控制”不能让上载的文件的文件名:他们是硬编码到预期包含字符串一个完整路径和提取最后一个反斜杠后的部分(或斜线,如果你是幸运的......)。 1 , 2

来了HTML5,
正如你在上面阅读,在“文件名模式”中规定:

如果列表为空,然后在选定的文件列表中的第一个文件的文件名,如果有的话,或空字符串:在获取时,必须返回字符串“\ fakepath \ C”。

他们指出,

这种“fakepath”的规定是历史的悲哀事故

由于历史原因,价值IDL属性前缀字符串“C:\ fakepath \”文件名。 一些传统用户代理实际上包含完整路径(这是一个安全漏洞)。 由于这一结果,获得从以向后兼容的方式值IDL属性的文件名是不平凡的。 下面的函数中提取在一个适当相容的方式的文件名:

 function extractFilename(path) { if (path.substr(0, 12) == "C:\\fakepath\\") return path.substr(12); // modern browser var x; x = path.lastIndexOf('/'); if (x >= 0) // Unix-based path return path.substr(x+1); x = path.lastIndexOf('\\'); if (x >= 0) // Windows-based path return path.substr(x+1); return path; // just the filename } 

注:我觉得这个功能是愚蠢的:整点是要始终有一个仿windows路径解析。所以第一个“如果”,不仅无益,反而甚至邀请了一个错误:想象与旧的浏览器上传用户:从文件c:\fakepath\Some folder\file.ext (因为这将返回: Some folder\file.ext )...
我会简单地使用:

function extractFilename(s){ 
  // returns string containing everything from the end of the string 
  //   that is not a back/forward slash or an empty string on error
  //   so one can check if return_value===''
  return (typeof s==='string' && (s=s.match(/[^\\\/]+$/)) && s[0]) || '';
} 

(如HTML5规范显然意)。

让我们回顾一下(获取路径/文件名):

  • 旧的浏览器(和新的浏览器,其中一个可以使此像IE> = 8的一个选项)将揭示全窗口/ UNIX路径
  • 少旧的浏览器不会透露任何路径,只是文件名(+扩展名)
  • 当前/未来/ HTML5的兼容的浏览器将始终预先挂起字符串: c:\fakepath\来获取文件输入的时的文件名
    最重要的是,他们将只返回第一个文件名(从“选择文件列表”)应在文件输入接受多个文件和用户选择多个文件。

因此,在最近的过去,现在和可预见的未来HTML5将一个通常只得到文件名。

这给我们带来了我们需要考察的最后一件事:这个/多文件“中选择的文件列表”,这使我们困惑的第三部分:

(HTML5)文件API

首先:“文件API”不应与“混淆文件系统API ”,这里是文件系统API的摘要:

本说明书中定义的API来导航文件系统层次结构,并限定通过其中的用户代理可暴露在用户的本地文件系统的沙盒部分,以Web应用程序的装置。 它建立在[FILE-WRITER-ED],而这又建立在[FILE-API-ED],各加入不同种的功能性。

在“用户的本地文件系统中的沙盒段”已经清楚地表明,一个不能用这个来获取用户的文件保持沙盒(所以没有这个问题有关外,尽管人们可以在用户选择的文件复制到持久本地存储和重新上传该副本使用AJAX等有用,因为在上传失败了“重试”。但它不会是一个指针可能会在平均时间已经改变了原来的文件)。
更重要的是,事实上只有WebKit的(认为旧版本的Chrome浏览器)来实现此功能,并规范很可能不是要生存,因为它is no more actively maintained, the specification is abandonned for the moment as it didn't get any significant traction

让我们继续用“ 文件API ”,
它是抽象的告诉我们:

本说明书提供了一种用于在web应用程序表示文件的对象,以及编程选择它们并访问他们的数据的API。 这包括:

  • 甲文件列表界面,它表示的单独选择的文件从底层系统的阵列。 用于选择的用户接口可通过调用<input type="file">即,当输入元件是在文件上传状态[HTML]。
  • 甲Blob接口,其表示不可变的原始二进制数据,并允许访问Blob对象作为一个单独的斑点内的字节的范围。
  • A文件接口,其包括只读信息关于文件属性,例如其名称和最后修改的文件的日期(在磁盘上)。
  • 甲的FileReader接口,它提供的方法来读取一个文件或BLOB,以及事件模型获得的结果的这些读取。
  • 对于二进制数据,如文件,使他们可以在web应用中引用中使用的URL方案。

所以, FileList可以由输入字段中的文件模式填充: <input type="file">
这意味着,上述所有关于价值属性仍然适用!

当输入场是在文件模式,它得到一个只读属性files ,其是阵列状的FileList object由访问引用所述输入元件的用户选择的文件(S)并且是(/是) FileList interface
我提到的files类型的-attribute FileList只读的 (文件API第5.2节) ? :

所述HTMLInputElement接口[HTML]具有类型文件清单的只读属性...

那么,怎么样拖放

从MDN的文档-选择使用拖放文件

真正的奇迹发生在降()函数:

 function drop(e) { e.stopPropagation(); e.preventDefault(); var dt = e.dataTransfer; var files = dt.files; handleFiles(files); } 

在这里,我们从事件中检索数据传递现场,然后将文件列表出来,它们递过来handleFiles()。 从这点上来说,处理中的文件是用户是否使用所述输入元件或拖放相同。

所以,(就像输入字段类型=“文件”)事件的dataTransfer属性有类似阵列的属性files这是一个类似数组的FileList object ,我们刚刚得知(上图),该文件清单是只读 ..

将文件列表中包含对用户选择(或丢弃在一个下拉目标)的文件(S)引用和一些属性。 从文件API 7.2节的文件属性 ,我们可以读到:

名称

该文件的名称; 在获取时,它必须返回该文件作为一个字符串的名称。 有不同的系统上众多的文件名变化; 这仅仅是文件名,不带路径信息。 在获取时,如果用户代理无法提供这方面的信息,他们必须返回空字符串。

lastModifiedDate

文件的最后修改日期。 在获取时,如果用户代理可以提供这方面的信息,这必须返回初始化文件的最后修改日期新的日期[HTML]对象。 如果最后修改日期和时间尚不清楚,该属性必须返回当前日期和时间作为Date对象。

并有一个size属性:

F.size是一样的fileBits斑点参数的大小,它必须是F的不可变的原始数据

同样,没有路,只是只读文件名。

从而:

  • (elm_input||event.dataTransfer).files给人的文件清单对象。
  • (elm_input||event.dataTransfer).files.length给出的文件数量。
  • (elm_input||event.dataTransfer).files[0]是所选择的第一个文件。
  • (elm_input||event.dataTransfer).files[0].name是所选择的第一个文件的文件名
    (这就是value被从输入类型=“文件”返回)。

这个怎么样“的二进制数据,如文件使用URL方案,使他们能够在web应用中引用”,肯定能容纳一个私有引用文件,用户选择的?

从文件API -一种用于Blob和File引用URL ,我们可以得知:

该规范定义了排序的URL的方案:
BLOB:550e8400-e29b-41d4-a716-446655440000#aboutABBA。

这些被存储在URL store (和浏览器甚至应该有自己的迷你HTTP服务器搭乘因此可以在CSS中,IMG SRC甚至XMLHttpRequest的使用这些网址。

人们可以创建这些Blob URL s的:

  • var myBlobURL=window.URL.createFor(object); 返回Blob URL这是第一次使用后自动作废。
  • var myBlobURL=window.URL.createObjectURL(object, flag_oneTimeOnly); 返回一个可重复使用Blob URL (除非flag_oneTImeOnly评估为真),并且可以与被撤销window.URL.revokeObjectURL(myBlobURL)

宾果你可能会认为......然而......该URL Store仅保持在会话期间(所以它会生存页面刷新,因为它仍然是同一个会话),该文件被卸载时,会丢失。

从MDN -使用对象的网址 :

对象URL是标识文件对象的字符串。 每次调用window.URL.createObjectURL(),创建一个唯一的对象URL,即使你创建的对象URL该文件了。 每一种必须被释放。 当文档被卸载时,它们会自动释放,如果你的页面使用这些动态的,你应该明确地调用window.URL.revokeObjectURL释放他们()

这意味着,即使当你存储Blob URL 字符串中的cookie或永久本地存储,该字符串将是一个新的会话也没用!

这应该给我们带来一个完整的圆,最后得出结论:
这是不可能的(重新)填充一个输入字段或用户选择的文件 (即不是在浏览器沙盒“本地存储”区域)。
(除非你强制用户使用Opera过时的版本,或强迫用户使用IE浏览器和某些ActiveX编码/模块(实现自定义的文件选择器),等等)

一些进一步阅读:
http://www.cs.tut.fi/~jkorpela/forms/file.html
https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
http://www.html5rocks.com/en/tutorials/file/filesystem/
http://www.html5rocks.com/en/tutorials/file/dndfiles/
http://caniuse.com/filereader
JavaScript权威指南 - 大卫·弗拉纳根,章-22:文件系统API
如何保存以备将来使用window.URL.createObjectURL()结果呢?
多久的Blob坚持?
如何解决C:\ fakepath?



Answer 2:

在窗体上创建一个输入字段。 当用户选择一个文件,结果复制到这个领域,是这样的:

jQuery('#inFile').change(
 function(){ jQuery('#inCopy').val( jQuery('#inFile').val() ); }
);

其实,结果是不完全复制,而不是它的拷贝“C:/ fakepath / SELECTED_FILE_NAME”。 虽然你不能设置一个文件输入的值,可以设置文本输入字段的值,而“C:/ fakepath /”,为服务器准备的表格。

现在,当服务器获取的形式回来了,检查文本输入字段。 如果它以“C:/ fakepath /”开头,那么用户必须选择一个新的文件,所以上传他们的新选择。 如果没有,那么用户选择了以前的选择,这不应该是因为一个问题,按照原来的问题,之前的选择已经与前应上传(至少有适当的编程,它可能)仍是在服务器上。



Answer 3:

在踩着由GitaarLAB提供的巨大的信息脚趾的危险,我可能会建议DaveWalley非常接近,提供解决问题的实际解决方案。 双方你帮了我很多这样的感谢。

我带回家的消息是,

  1. 该文件输入提供了一个单向街。 它坐在那里等待处理你的下一个上传。 这就是它所做的一切,漂亮多了。 它接收
  2. 一个DIV或只读附近的标签,为您的文件输入可以做服务文本形式输入。 也就是说,它可以用来告诉用户,“这是什么目前已上传:” - 文件名显示将需要从你的服务器端逻辑填充。

因此,一个基本的使用情况是:

  • 用户通过上传表单输入文件的网页上
  • 服务器端逻辑存储文件
  • 在Ajax周期或网页重新加载服务器端代码标识文件名的字符串在div写,“这是什么目前上传”
  • 该文件输入可以重新提出过,让用户欢迎上传另一个文件以及/代替。

您可能需要做更多的工作来处理“*需要”验证但那是另一回事。



Answer 4:

如果所有你想要的只是一个临时的持久性文件的数据,例如,如果有一个页面上的错误,或者如果你想有一个确认页面,将数据提交到数据库之前,那么这通常与配售完成该文件放在临时的,将数据保持在隐藏字段。

这不重新填充文件输入字段。 但你也可以只取输入文件的名称和旁边的文件输入框放置。

像这样:

<input type=hidden name="filename" value="<?php echo $filename; ?>" />
<input type="file" name="uploadfile" size="50" />

<?php if (!empty($filename)) echo $filename; ?>


文章来源: Remember and Repopulate File Input [duplicate]