【HTML】input type=fileのC: akepath問題


input type="file"でファイルを選択すると、選択されたファイルが実際に位置しているローカルディスクのフルパスとは違うパス値として自動的にC:\fakepath\(選択したファイル名)に変換されることがある。
ググってみると昨今のブラウザのセキュリティ仕様で勝手にそういう風に変換されるらしい。
ただこれはブラウザ毎にも少し異なる動きをするし、ローカルのHTMLを直接ブラウザで開いた場合やサーバ上に存在するHTMLを開いた場合でも異なる。
実験して分かった範囲をまとめてみる。


 


 


下記のようなHTMLを用意する。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
<HTML>  
	<head>  
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
		<META http-equiv="X-UA-Compatible" content="IE=edge">  
	&lt;title&gt;input type=file test&lt;/title&gt;  
	  
	&lt;script type="text/javascript"&gt;  
	&lt;!--  
		function onchangeTest(){  
			var input_type_file_test_element = document.getElementById("input_type_file_test");  
			var input_type_text_test_element = document.getElementById("input_type_text_test");  
			input_type_text_test_element.value = input_type_file_test_element.value;  
		};  
	// --&gt;  
	&lt;/script&gt;  
	  
&lt;/head&gt;  
&lt;body&gt;  
	■input type="file"のテストオブジェクト↓&lt;br/&gt;  
	&lt;input type="file" value="ファイル選択のテストだよ~ん" id="input_type_file_test" size="100" onchange="onchangeTest();"&gt;&lt;br/&gt;  
	&lt;br/&gt;  
	■選択されたファイル名↓&lt;br/&gt;  
	&lt;input type="text" id="input_type_text_test" value="" style="border:none;" size="100" readonly&gt;&lt;br/&gt;  
&lt;/body&gt;  

</html>


このHTMLはinput type="file"として定義したID=input_type_file_testを配置し
そこで選択したファイルの値(value)をreadonlyのinput type="text"のID=input_type_text_testに転記するだけの簡単なものである。
→「転記」の部分はjavascriptで行っている

で、これをローカルに「.html」で保存する。
これをダブルクリックで開く(ないし開いてるブラウザの上にドラッグ&ドロップする)ことを「ローカルで開く」
このhtmlをWebサーバに配備してそのURLをたたいて開くことを「サーバで開く」
という風に大分類する。
さらに「サーバで開く」に関しては、
例えばtomcat上で自分のマシン上に展開している「localhost~」というドメインのWebサーバで開くような行為等、
つまりセグメントがローカルネットワーク内に存在するドメインのWebサーバで開くことを「サーバで開く(LAN)」
グローバルIPが振られている外部のドメインのWebサーバで開くことを「サーバで開く(WAN)」とする。(これらの表現もどうかと思うが…面倒なのでこれでいいや)

↑のように分類すると、「■選択されたファイル名↓」に表示される内容が「C:\fakepath\~~」になるかどうかは以下のようになる。
(OSは全部Win7)

■凡例
○:選択されたファイルの実際のフルパスがそのまま表示
×:C:\fakepath\~~になる
:そもそもパス部分が表示されない(ファイル名部分しか表示されない)

ブラウザローカルで開くサーバで開く(LAN)サーバで開く(WAN)

IE(11) ×
FireFox(45.01)
Google Chrome(49.0.2623) × × ×


ってかんじ。


FireFoxは一貫して、そもそもパスを表示させていない。
ブラウザ自体がこういう仕様のようだ。

Google Chromeはローカルで開いた時から既に「C:\fakepath\~~」とするが、
IEはローカルで開いた時、もしくはローカルのWebサーバ上で開いた時までは元々のフルパスをそのまま表示する。
いずれにしても外部のWebサーバ上で開いた時には「C:\fakepath\~~」になる。




ちなみに、↑までの話はjavascriptで転記"される側"の、つまり「■選択されたファイル名↓」の部分に表示される値がどーなるかという話であるが、
そもそも元のオブジェクトであるinput type="file"で選択されたファイル名をブラウザがどう表示するかは、IEかそれ以外下で大きく分かれており、それぞれ下記のようなイメージになる。

IEGoogle Chrome/Fire Fox



IEは灰色のテキストボックスに似た入力値の部分に選択したファイルのフルパスが表示され、その右隣にファイル選択ウィンドウを開く「参照」ボタンがある。
対してFire FoxとGoogle Chromeは、ファイル選択ウィンドウを開く「参照」ボタンがまず最初に来て、選択したファイルの「ファイル名」だけをその右側に表示する。(↑はFire Foxの画面ショットだがGoogle Chromeも同じ)
GUIとしてはFire FoxとGoogle Chromeはほぼ同じで、つまり選択したファイルに関してはinput type="file"上としては「ファイル名」までしか表示させないようにしている。
Fire FoxもGoogle Chromeも、javascriptでinput type="file"のvalueをとったときに初めてそのファイルのフルパスまで扱うことができるが、
Google Chromeは「ローカルで開く」段階から既に「C:\fakepath\~~」だし、
Fire Foxは元からそもそもパス部分を扱っていない。
結果的にFire FoxとGoogle Chromeはどういった環境下においても選択したローカルファイルのフルパスをブラウザ上に残さないように細工されている。
(やっぱりIEだけが……)




javascriptのデバッグを仕掛けておいてブレークポイント仕込んで値を見てみる、とかすると、
○のケース-つまり元々のフルパスと同じ値を引き継いでいるケース-では別段なにも不思議に思わないが、
×のケースではなぜか突然C:\fakepath\(選択したファイル名)に変わっていて一瞬「!?」って思う。
HTMLやjavascriptのコーディングでどうこうできる範囲を超えた部分で勝手にvalueが書き換わるので、気持ち悪いのが正直なところだ。

この挙動、パス部分を偽造することが目的なのだろうか…
ググっても出てくるのは「セキュリティの都合で」とかそういう断片的な情報だけなのだが
パス部分の偽造が目的なら、実在しない変なパスに勝手に変換されるよりFire Foxがやっているようにファイル名だけ出してもらえる方がシンプルでわかりやすい。
”実在しない変なパスに勝手に変換される”という部分が作り手からすると気持ち悪さを感じる要素の一つになってしまっているように思う。