過去可很簡單地使用 JavaScript 將 input file 的檔案路徑,更新 DOM ,例如載入不同圖片變更顯示內容
但在下最近打算編寫一個類似的程式,發現不出錯誤……
基本 Input File
<input type="file"/>
原來基於安全理由,現今的網頁瀏覽器都不會在 input file 顯示完整檔案路徑
即使使用 JavaScript 讀取 input file 的 value 都只會顯示 檔案名 或 C:\fakepath\檔案名
來保障使用者的目錄結構
<input type="file" onchange="window.alert(this.value);"/>
createObjectURL
如果需要達到互動載入檔案的效果,需要借用 createObjectURL 的 Web APIcreateObejctURL 是一種 HTML5 的 Web API 技術,能夠將資源轉換成 HTML 的 二進位大型物件 (Binary Large Object (blob)) 內容
createObjectURL 會傳回一個類似 base64 的字串,例如 blob:<domain>/6bda40ca-97e4-4f99-aef2-0d119bcbe3fe
實際這是一組 全域唯一識別碼 (Globally Unique Identifier (GUID))
這組字串只是一個二進制資料的 唯一ID ,指向保存在網頁瀏覽器記憶體中的資料
GUID 指向的資料 會在關閉網頁瀏覽器後 或執行 revokeObjectURL 在不關閉網頁瀏覽器的情況下釋放記憶體
而且由於資料轉換成 HTML 的 blob 並不會顯示使用者的系統結構,相對比較安全
但 createObjectURL 暫時未有統一實作的設計,因此會使用
function createObjectGUID(object) { if (window.createObjcectURL != undefined) { object = window.createOjcectURL(object); } else if (window.URL != undefined) { object = window.URL.createObjectURL(object); } else if (window.webkitURL != undefined) { object = window.webkitURL.createObjectURL(object); } else { object = null; } return object; } function deleteObjectGUID(guid) { if (window.revokeObjectURL != undefined) { window.revokeObjectURL(guid); } else if (window.URL != undefined) { window.URL.revokeObjectURL(guid); } else if (window.webkitURL != undefined) { window.webkitURL.revokeObjectURL(guid); } } function importImageFile(image, input) { var guid = createObjectGUID(input.files[0]); if (guid != null) { image.src = guid; if (image.parentNode instanceof HTMLAnchorElement) { image.parentNode.href = guid; } } }建立 或 刪除 GUID 及 被指派的 Object 資料
測試效果
<a target="_blank"><img id="image-container" src="" width="600" height="400" alt="Test Image" title="Test Image"/></a>
<input type="file" onchange="importImageFile(document.getElementById('image-container'), this);"/>input file 測試載入 HTML blob 到 HTML 圖像的效果
FileReader
FileReader 同樣是 HTML5 Web API 的技術之一,可以安全地透過 JavaScript 將檔案的內容在頁面上顯示function importTextFile(text, input) { var fileReader = new FileReader(); fileReader.readAsText(input.files[0]); fileReader.onload = function(event) { text.value = fileReader.result; }; }讀取文件內容
測試效果
<textarea id="text-container" style="font-family: 'Courier New';" rows="10" cols="30" readonly="readonly"></textarea>
<input type="file" onchange="importImageFile(document.getElementById('text-container'), this);"/>input file 測試載入 檔案內容 到 HTML textarea 的效果
檔案過濾
HTML5 新增 accept 屬性可以方便過濾檔案accept 支援
- MIME類型
- 例如 image/png 、 video/mp4 、 text/*
- 副案名 (不需要使用 * (星號))
- 例如 .png 、 .mp4
副案名就很簡單,但 MIME類型 每個系統支援都不相同
以 Firefox 為例,可以到 about:config 了解系統能夠支援的 MIME類型
了解系統支援的 MIME類型 ,按需要增加過濾內容
增加過濾內容後,選擇檔案時可以過濾檔案類型
<input type="file" onclick="this.accept = document.getElementById('file-accept').value;"/> <label>過濾內容:<input id="file-accept" style="font-family: 'Courier New'; width: 600px;" type="text" value="audio/mpeg, audio/ogg, audio/x-wav, image/gif, image/jpeg, image/png, image/x-ms-bmp, video/mp4, video/ogg, video/webm, .aac"/></label>借用 input text 來改變 input file 的 accept 內容,方便測試
總結
在下以前都曾經製作過類似的網頁程式,但當時沒有思考安全問題直到今天再寫類似的程式時,發現不能正常運作,翻查資料才發現這個安全設計早在 2009年 已經修改,因此尋找解決方法
但有不少解決方法都要建議降低安全性以配合此操作
在下並不建議降低安全性來遷就這個程式的操作需要,而且使用者未必懂得修改安全性設定,因此還是要不斷尋找資料
而且還可以不需要借助 第三方工具 及 起動網頁伺服器 便直接使用 HTML5 的 Web API 安全地存取檔案內容
設計互動網頁便更加簡單及方便
沒有留言 :
張貼留言