独孤求败——浅谈FireFox中file控件不可能取到客户端文件的一体化路径的标题

    相信广大人都施用过<input
type=”file”/>这样的HTML控件,它看起来卓殊普通,是我们在做Web应用程序中用来上传客户端本地文件时不得缺失的控件,可是多年来本身意识那些控件在新型的Fire福克斯浏览器(或者最新的IE8中也会存在那一个题目,我没有品味过,读者可以试一下)中却错过了功用,导致大家在通过那些控件的value属性获得的值中只含有了文本名而没有公文路径,那个在IE7中是可以正常获取到全文件名的(即文件完整路径+文件名)。IE7和一大半当下盛行的浏览器(如FireFox2本子)都足以拿走到文件的不二法门,可是Fire福克斯3却相当,我查了很多材料,发现那是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"&gt;
<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中的结果:

图片 1
运行后在FireFox3中的结果:

图片 2

      
那么我什么才能在FireFox3中获取当地文件的途径呢?就像是上边我在IE7中收获的不胜值一样!暂且撇开这么些题目,先说说在FireFox3中哪些上传一个文本呢。既然Fire福克斯3中校取得当地文件的门道的艺术当做一个安全隐患被取缔了,那么它自然有有关的形式来缓解那一个难点,否则FireFox3就无法促成在客户端上传文件的机能了,似乎前两日我的一个同事说的一致,要真是如此,Fire福克斯就废了!其实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"&gt;

<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图片 3
           
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图片 4
           
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图片 5
    <input type=”file”
name=”fileBrowser” size=”125″
onchange=”readFile(this)” />
    </form>
</body>
</html>

   
首先大家须要判定用户浏览器的花色来挑选执行不一的function,IE中一直调用Scripting.FileSystemObject那个ActiveXObject,然而假设用户的IE没有打开“对未标记为可高枕无忧实施脚本的ActiveX控件开端化并履行脚本”的话是无法履行那行代码的,在本子中提交了提拔,告诉用户必须将以此选项打开。

图片 6

   
IE的难点不大,因为大家一齐可以直接使用input的value值得到文件的门路,那里给出的点子紧要是可以赢得文件的二进制数据,重点看看在FireFox3中是如何是好的。FireFox3中须求用户在配备页面中添加一个名号为signed.applets.codebase_principal_support的键值,将值设为true,然后就足以经过代码中付出的点子得到文件的本地路径了,同样也得以拿走文件的二进制数据。上边是在ForeFox3中中标获得到当地文件路径的截图。

图片 7

    有关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中,我都可以获取到用户所选文件的地面路径,然后保留在页面的隐藏域中,当用户提交页面时,服务器端代码便可以通过页面隐藏域中的值得到用户所选用的文书的门径,从而上传文件到服务器。

相关文章