画像アップロード画像をアップロードする機会というのは結構あると思う。 その際、選択した画像を表示して確認しながらアップロードしたいと思うのはごく自然なことだが、それがなかなかうまくいかない。 試した限りでは、それができるブラウザはかなり限定される。 ファイルをアップロードするには、form要素に<input type="file" ...>を記述する。 そこからユーザーが選択した画像ファイルのデータを取得し、img要素のsrc属性に設定する必要がある。 当然、その画像データはユーザーのローカルな環境から取得したい。 IE6まず、IE6では簡単にできる。サンプルはここ。 JavaScript抜粋 document.images[0].src = document.forms[0].file01.value; アップロード用のinput要素から選択されたファイルのフルパスを取得し、それをimg要素のsrc属性に指定しているだけだ。 ただし、この方法はIE7以降では、デフォルトの設定のままだとできない(らしい)。 試したわけではないが。 うちはWindowsは未だにXPだし、IEも6のままである。 IEには興味もないしほとんど使わないので、アップデートは面倒くさい。 ということで、IE7以降の確認はしないことにする。 久しぶりにIE6を使用したが、かなりイライラしてしまった。 まあ、それは置いといて。 IE7以降では、アップロード用のinput要素からはファイルのフルパスを取得できない。 フルパスが取得できると、ユーザーのローカルな環境の構造が分かってしまうので、セキュリティ上危険ということだ。 他のブラウザも今はフルパスが取得できるものはないはずだ。 逆にできるブラウザというのは、セキュリティに関する考慮が無いに等しいので、使わない方がいいだろう。 ということで、IEにせよ他のブラウザにせよ、この方法が今後使えるという可能性は皆無だろう。 Firefoxでは他のブラウザではどうか? 実はFirefoxではできる。 当然IE6のようにセキュリティの穴を利用するようなものではなく、真当な方法だ。 方法は3つある。 そのうち2つはFirefox独自の方法。 もう1つはHTML5のFile APIを使う方法だ。 ・Firefox独自の方法その1サンプルはここ。 JavaScript抜粋 var file = document.forms[0].file01.files[0]; var name = file.fileName; var pre = "data:image/" + name.substring(name.lastIndexOf(".") + 1) + ";base64,"; document.images[0].src = pre + btoa(file.getAsBinary()); "data:image/xxx;base64,"の後に、画像ファイルのバイナリデータをBase64エンコードしたものを連結し、imgのsrcに指定している。 xxxの部分は画像のフォーマットで、ファイルの拡張子をそのまま使っている。 これは最初にたどり着いた方法で、調べるのにかなり苦労した。 以下は参考にさせてもらったページ。 フォームの file 入力欄と、 files リスト [javascript] base64 エンコードしたい Ajax:画像を取得して表示する(Firefox) JavaScriptでバイナリを扱う & ... 実はもう少し簡単にできるのだが、それは後から分かったことだ。 ・Firefox独自の方法その2ということで、次は上の方法よりもっと簡単な方法。 サンプルはここ。 JavaScript抜粋 var file = document.forms[0].file01.files[0]; document.images[0].src = file.getAsDataURL(); 要するにFileオブジェクトのgetAsDataURL()メソッドが上と同じことを自動的にやってくれるようだ。 ・HTML5のFile APIを使う方法現在策定が進んでいるHTML5の中に"File API"という仕様があり、これを使えばできる。 記述は少し面倒だ。 ただし、今現在File APIの機能は、Firefox 3.6で"HTML5 parser"という機能を有効にしないと使うことができない。 有効にする方法は、アドレスバーに"about:config"と入力し、"html5.enable"の項目上で右クリック→"切り替え"を選択。 これは自己責任でということのようだ。 で、サンプルはここ。 JavaScript抜粋 var reader = new FileReader(); var file = document.forms[0].file01.files[0]; reader.onloadend = function(ev){ document.images[0].src = reader.result; }; reader.readAsDataURL(file); 結構面倒だが、いろいろ考えた結果なのだろう。 以下は参考にさせてもらったページ。 HTML5 Drag and Drop APIとFile APIのデモ html5-developers-jp | Google グループ: File APIのサンプル File APIのサンプル ということで、HTML5が普及すれば、どのブラウザでも同じ記述で実現できるようになるだろう。 早くそうならないかな。 その他今のところ、まともにできるのはFirefoxだけだと思う。 いろいろ試してみたが、他のブラウザではどうもできそうにない。 似たようなことができるjQueryのプラグインはあるようだ。 このページ参考。 ただし、やってみれば分かるが、ここでやりたいこととは全く異なる。 詳しく見てないが、このプラグインは、ユーザーが画像を選択した時点で、サーバーに画像データを送信していると思われる。 それを一旦一時的な場所に保管しておき、その後ユーザーが確定した段階で正規の場所に移すということなのだろう。 でも、このプラグインの作者は最初からこのような仕様にしたかったのだろうか? 確かにそのようにするべきだという人もいるようだ。 このページ参照。 だが、個人的にはそんな方法がいいやり方だとはとても思えない。 まず、実際にデータが送信されるので当然だが、かなり遅いし、帯域も無駄だ。 サーバー設計者にしても、ユーザーが確定するとは限らないので、その場合の考慮をする必要がある。 ユーザーにしても、気軽に選択した画像ファイルがセキュリティ上問題のあるものだったとしても、実際に送信されてしまう。 確定しなかったとしても、サーバー側でそのファイルを削除してくれる保証はどこにもない。 そんなことをするくらいなら、画像を表示するのはあきらめて、よく確認してから送信するように催促する方がマシではないだろうか。 誰がどう考えても、サーバーにデータを送ることなしに、ユーザーのローカルな環境から画像を表示するほうがいいに決まっている。 上のようなプラグインが存在するということは、逆にそれができないということなんだろうな。 結論特に結論というものはないが、早くHTML5が普及してほしいな。 あとは、何だかんだいっても、Firefoxが一番、細かいところまでよく考えられていて、真面目なブラウザだという気がする。 |
| << 前記事(2010/04/21) | ブログのトップへ | 後記事(2010/05/15) >> |
| タイトル (本文) | ブログ名/日時 |
|---|
| 内 容 | ニックネーム/日時 |
|---|
| << 前記事(2010/04/21) | ブログのトップへ | 後記事(2010/05/15) >> |