相信很多人都使用过<input type="file"/>这样的HTML控件,它看起来非常普通,是我们在做Web应用程序中用于上传客户端本地文件时不可缺少的控件,然而最近我发现这个控件在最新的FireFox浏览器(或者最新的IE8中也会存在这个问题,我没有尝试过,读者可以试一下)中却失去了效果,导致我们在通过这个控件的value属性得到的值中只包含了文件名而没有文件路径,这个在IE7中是可以正常获取到全文件名的(即文件完整路径+文件名)。IE7和大部分当前流行的浏览器(如FireFox2版本)都可以获取到文件的路径,但是FireFox3却不行,我查了很多资料,发现这是FireFox3为了弥补在低版本中可能会引起安全问题的一个漏洞,据说黑客会通过FireFox的这一安全隐患向服务器上传文件!其实我也搞不懂,不就是本地文件的路径么?怎么会影响到服务器的安全问题呢?看来高手们还真的很强!!

来说说我为什么要得到本地所选的文件的路径。大家都知道163邮箱,里面在上传邮件附件的时候是允许选择多附件的,我要做的功能类似于这个,不过我在这里并不是要研究163是如何实现这个功能,我只想在用户选择文件的时候动态在一个Div中添加他所选择的文件的信息和一个删除按钮,然后将这个文件的信息保存在页面的一个隐藏域中,当用户保存页面时服务器端代码根据页面隐藏域中的信息将用户所选的文件上传到服务器上。当然,页面隐藏域中的信息至少要包含用户本地所选文件的路径,否则就不知道在什么地方去找文件了。有关如何实现动态添加HTML节点不是本文的重点,这里我也不贴代码了,下面说说我所遇到的问题。

下面是一段用于测试问题的代码。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Untitled Page</title>
</head>
<body>
    <input id="File1" type="file" /><input id="btAdd" type="button" value="Add" onclick="alert(document.getElementById('File1').value);" />
</body>
</html>

运行后在IE7中的结果:

运行后在FireFox3中的结果:

那么我如何才能在FireFox3中取得本地文件的路径呢?就像上面我在IE7中得到的那个值一样!暂且撇开这个问题,先说说在FireFox3中如何上传一个文件吧。既然FireFox3中将获取本地文件的路径的方法当做一个安全隐患被禁止了,那么它一定有相关的方法来解决这个问题,否则FireFox3就不能实现在客户端上传文件的功能了,就像前两天我的一个同事说的一样,要真是这样,FireFox就废了!其实FireFox3中引入了一个新的接口用来解决这个问题,那就是nsIDOMFile,它专门被用来从客户端的input type="file"的控件中获取文件数据,这样就可以将本地的文件保存到服务器上。这是一个非常好的解决办法,以至于我们在FireFox3中开发这样的应用程序时比先前简单获取value值然后再通过服务器端代码上传文件要简单许多,不过令人担忧的是,这个接口只适用于FireFox,在IE和其它的浏览器中并不支持。一会儿再说如何解决浏览器的兼容性问题,先看一下在FireFox3中怎么使用nsIDOMFile。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>input type=file & Firefox 3</title>
</head>

<body>
    
<h1>input type=file & Firefox 3</h1>
    
<script type="text/javascript">
// <![CDATA[

function inputFileOnChange() {    
    if(document.getElementById('my-file').files) {
        // Support: nsIDOMFile, nsIDOMFileList
        alert('value: ' + document.getElementById('my-file').value);
        alert('files.length: ' + document.getElementById('my-file').files.length);
        alert('fileName: ' + document.getElementById('my-file').files.item(0).fileName);
        alert('fileSize: ' + document.getElementById('my-file').files.item(0).fileSize);
        alert('dataurl: ' + document.getElementById('my-file').files.item(0).getAsDataURL());
        alert('data: ' + document.getElementById('my-file').files.item(0).getAsBinary());
        alert('datatext: ' + document.getElementById('my-file').files.item(0).getAsText("utf-8"));
    };
};

// ]]>
</script>
    
<div>
    <input type="file" name="my-file" id="my-file" onchange="inputFileOnChange();" />
</div>
    
</body>
</html>

document.getElementById('my-file').files方法用于获取到用户所选择的文件的集合,一般情况下都是选择单一文件(貌似FireFox这样做是支持多文件选择的,不过没有试过,读者可以自己去尝试),item数组可以得到其中的某一个文件,然后我们就可以使用nsIDOMFile所提供的属性和方法了。它包括2个属性和3个方法:

fileName:用于获取到用户所选文件的名称,这和直接取value值所得到的结果一样。

fileSize:得到用户所选文件的大小。

getAsBinary():得到用户所选文件的二进制数据。

getAsDataURL():得到用户所选文件的路径,该路径被加密了,目前只能在FireFox中使用。

getAsText():得到用户所选文件的指定字符编码的文本。

读者可以参考这个地址:https://developer.mozilla.org/en/nsIDOMFile

有一点需要说明,方法getAsDataURL()可以取得用户所选文件的本地路径,但是这个路径的字符串文本被FireFox加密了,并且这段密文只能被FireFox识别,其它的浏览器不能识别,也就是说我将被加密后的路径直接赋值给一个img标签的src属性,在FireFox中是可以直接显示出图片的,而在IE中却不行。从这一点来看,FireFox是不是有点王者风范呢?居然连大名鼎鼎的IE都不支持!

再回到本文一开始所提的那个问题上来。即然我不能在FireFox中得到用户所选文件的本地路径,而且采用getAsDataURL()方法得到的这个路径也不能体现通用性,那怎么才能彻底解决这个问题呢?简单思考一下,浏览器为什么能够调用OS的文件打开对话框,从而进一步得到用户所选的文件的信息呢?浏览器不是仅仅只能解释HTML文本么?没错,这个是浏览器的基本功能,至于如果调用OS提供的功能接口,那是浏览器的各个不同厂商自己要做的工作,这个似乎没有一个统一的标准,也不会被列入到W3C的规范中,FireFox3就是一个特例。这样看来,我们只有自己编写代码来调用OS的文件打开对话框了,这看起来是一件非常辛苦的事情,最好的办法莫过于编写ActiveX控件嵌入到浏览器中来执行,幸运的是IE和FireFox都提供了现成的方法供我们调用,我们只需要在js脚本中调用即可。当得知这一点时,我差点高兴得一晚上没有睡觉。

好了,现在来看我是怎么做的了!

<html>
<head>
    <title>Untitled Page</title>

<script type="text/javascript">
function readFile(fileBrowser) {
    if (navigator.userAgent.indexOf("MSIE")!=-1)
        readFileIE(fileBrowser);
    else if (navigator.userAgent.indexOf("Firefox")!=-1 || navigator.userAgent.indexOf("Mozilla")!=-1)
        readFileFirefox(fileBrowser);
    else
        alert("Not IE or Firefox (userAgent=" + navigator.userAgent + ")");
}

function readFileFirefox(fileBrowser) {
    try {
        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
    } 
    catch (e) {
        alert('Unable to access local files due to browser security settings. To overcome this, follow these steps: (1) Enter "about:config" in the URL field; (2) Right click and select New->Boolean; (3) Enter "signed.applets.codebase_principal_support" (without the quotes) as a new preference name; (4) Click OK and try loading the file again.');
        return;
    }

var fileName=fileBrowser.value;
    var file = Components.classes["@mozilla.org/file/local;1"]
        .createInstance(Components.interfaces.nsILocalFile);
    try {
        // Back slashes for windows
        file.initWithPath( fileName.replace(/\//g, "\\\\") );
    }
    catch(e) {
        if (e.result!=Components.results.NS_ERROR_FILE_UNRECOGNIZED_PATH) throw e;
        alert("File '" + fileName + "' cannot be loaded: relative paths are not allowed. Please provide an absolute path to this file.");
        return;
    }

if ( file.exists() == false ) {
        alert("File '" + fileName + "' not found.");
        return;
    }
    alert(file.path); // I test to get the local file's path.
    var is = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance( Components.interfaces.nsIFileInputStream );
    try { is.init( file,0x01, 00004, null); }
    catch (e) {
        if (e.result!=Components.results.NS_ERROR_FILE_ACCESS_DENIED) throw e;
        alert("Unable to access local file '" + fileName + "' because of file permissions. Make sure the file and/or parent directories are readable.");
        return;
    }
    var sis = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance( Components.interfaces.nsIScriptableInputStream );
    sis.init( is );
    var data = sis.read( sis.available() );

alert("Data from file: " + data); // I test to get the local file's data.
}

function readFileIE(fileBrowser) {
    var data;
    try {
        var fso = new ActiveXObject("Scripting.FileSystemObject");

var fileName=fso.GetAbsolutePathName(fileBrowser.value);
        if (!fso.FileExists(fileName)) {
            alert("File '" + fileName + "' not found.");
            return;
        }

var file = fso.OpenTextFile(fileName, 1);

data = file.ReadAll();
        alert("Data from file: " + data);
        file.Close();
    }
    catch(e) {
        if (e.number == -2146827859) {
            // This is what we get if the browser's security settings forbid
            // the use of the FileSystemObject ActiveX control
            alert('Unable to access local files due to browser security settings. To overcome this, go to Tools->Internet Options->Security->Custom Level. Find the setting for "Initialize and script ActiveX controls not marked as safe" and change it to "Enable" or "Prompt"');
        }
        else if (e.number == -2146828218) {
            // This is what we get if the browser can't access the file
            // because of file permissions
            alert("Unable to access local file '" + fileName + "' because of file permissions. Make sure the file and/or parent directories are readable.");
        }
        else throw e;
    }
}
    </script>

</head>
<body>
    <form name="form1">
    Browse to select a file
    <input type="file" name="fileBrowser" size="125" onchange="readFile(this)" />
    </form>
</body>
</html>

首先我们需要判断用户浏览器的类型来选择执行不同的function,IE中直接调用Scripting.FileSystemObject这个ActiveXObject,不过如果用户的IE没有打开“对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本”的话是不能执行这行代码的,在脚本中给出了提示,告诉用户必须将这个选项打开。

IE的问题不大,因为我们完全可以直接使用input的value值得到文件的路径,这里给出的方法主要是可以得到文件的二进制数据,重点看看在FireFox3中是如何做的。FireFox3中需要用户在配置页面中添加一个名称为signed.applets.codebase_principal_support的键值,将值设为true,然后就可以通过代码中给出的方法得到文件的本地路径了,同样也可以得到文件的二进制数据。下面是在ForeFox3中成功获取到本地文件路径的截图。

有关about:config和如何配置FireFox浏览器,读者可以参考下面的链接:

http://www.shanzhuang.com/content/aboutconfig%E8%AE%BE%E7%BD%AE%E6%8A%80%E5%B7%A7

http://www.cnblogs.com/looky/archive/2008/03/18/1111859.html

这样,我的问题就可以解决了,不管是在IE中,还是在FireFox中,我都可以获取到用户所选文件的本地路径,然后保存在页面的隐藏域中,当用户提交页面时,服务器端代码便可以通过页面隐藏域中的值得到用户所选择的文件的路径,从而上传文件到服务器。

转载于:https://www.cnblogs.com/jaxu/archive/2009/04/19/1439016.html

独孤求败——浅谈FireFox中file控件不能取到客户端文件的完整路径的问题相关推荐

  1. kotlin中mainactivity无法直接调用xml中的控件_使用52North 客户端接口调用OGC WPS服务...

    52°North是一个来自研究机构.工业界和公共行政管理界的研究者组成的开放国际合作组织,他们通过协作研发流程促进地理信息学创新.具体来说他们开发新的地理信息概念和技术,例如用于管理时空测量数据,以及 ...

  2. LabVIEW中ActiveX控件、ActiveX服务器和类型库注册

    LabVIEW中ActiveX控件.ActiveX服务器和类型库注册 如何在计算机上手动注册ActiveX控件(.ocx ).ActiveX服务器(.DLL和.EXE)以及类型库(.TLB )? 在L ...

  3. file相对路径java_浅谈java 中文件的读取File、以及相对路径的问题

    一.对于java项目中文件的读取 1.使用system 或是 系统的properties对象 ①直接是使用 string relativelypath=system.getproperty(" ...

  4. html代码id,浅谈html中id和name的区别实例代码

    浅谈html中id和name的区别实例代码 更新时间:2008年07月28日 23:00:55   作者: 这个是form里面的name与id的区别 我们可以通过一段代码来分析一下其中的微妙差别: 在 ...

  5. 浅谈EVE中的经济学问题

    浅谈EVE中的经济学问题 1.16340005 本人学院 目录 1.EVE中的货币 2.EVE中的市场 3.EVE中的战争 1.EVE中的货币 在EVE这个世界中,如果对制造业有着一定了解的话,你一定 ...

  6. Asp.Net中验证控件简单分析

    为了实现验证,.net提供了一个javascript脚本,当我们生成一个asp.net页面时,通过查看页面源代码的方式,会发现都调用了下面一个javascript文件: <script src= ...

  7. 浅谈JAVA中如何利用socket进行网络编程(二)

    转自:http://developer.51cto.com/art/201106/268386.htm Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以 ...

  8. [转]ASP中ActiveX控件的内嵌及调用

    懂ASP(Active Server Pages)的人很多,但能用ASP自如地调用ActiveX控件的人却不多:如果不调用ActiveX控件,则可以说微软当初设计ASP的初衷根本没有达到.众所周知,A ...

  9. 【网摘】 浅谈HTTP中GET与POST的区别

    文章出处:http://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html 浅谈HTTP中Get与Post的区别 Http定义了与服务器交互的不 ...

  10. Html input file控件使用accept过滤 限制的文件类型

    Html input file控件使用accept过滤文件 ,老的浏览器不支持,不过对应新的浏览器还是方便很多 <input type="file" accept=" ...

最新文章

  1. java计算程序运行时间_C#里面的时间,如何计算一个程序运行花费的时间
  2. mac文件夹中如何给文件重命名,快捷键是什么
  3. eclipse插件 --js
  4. Java 改变cmd颜色_9 个小技巧让你的 if else 看起来更优雅!
  5. Linux网络编程 | Socket编程(二)TCPSocket的封装、TCP服务器多进程、多线程版本的实现
  6. Mac Pro 修改环境变量
  7. C语言字符串库函数的实现
  8. Python程序员培训计划
  9. 【Matlab编程】新手入门第五天
  10. 【NAACL 2021】RCI:在基于 Transformer 的表格问答中行和列语义捕获
  11. Excel导入poi、导出poi
  12. 如何区分np.random.normal()、np.random.randn()、np.random.randint()、np.random.random()、np.random.choice()
  13. 统计了300课时的代码,得到学Python需要掌握的1024个英语单词
  14. 公网IP和内网IP的区别
  15. 2015华为Word Maze 是一个网络小游戏,你需要找到以字母标注的食物
  16. 武汉大学IGS数据中心网站的下载方法
  17. 求矩形中心点坐标编程c语言,三角函数在图形学里的应用(四) ​已知矩形的中心点、边长、phi求四个顶点的坐标...
  18. 投入时间培训新人值得吗?
  19. 联想YOGA 14s 2021标压锐龙版和低压英特尔版选哪个 哪个更值得入手
  20. python获取excel单元格内容作为文件名_python——根据电子表格的数据自动查找文件...

热门文章

  1. matlab fft能量守恒吗,功能关系 能量守恒定律
  2. win7系统备份还原软件_十分不错的系统还原工具 一键还原备份系统软件 一键还原备份SGIMINI4.0通用版本...
  3. Hrbust 2064 萌萌哒十五酱的宠物~(树链剖分+线段树)
  4. 数学中最神奇的常数-无理数e的由来
  5. Schematic export failed or was cancelled. Please consult the transcript in the source windo
  6. conda 安装完了之后安装torch总是失败
  7. 制造业信息化管理蓝图
  8. 制造业数字化转型的意义是什么?
  9. 基于docker的redis4.0单机集群搭建
  10. foxmail 登陆gmail报密码错误