FE
HTML
基礎的設置:
<form enctype="multipart/form-data"><input id="file" type="file" multiple="multiple" name="file" accept="..."><input type="submit" value="上傳">
</form>
復制代碼
Form的enctype屬性
enctype這個屬性管理的是表單的MIME編碼,它一共有三個屬性:
值 | 描述 |
---|---|
application/x-www-form-urlencoded | 在發送前編碼所有字符(默認) |
multipart/form-data | 不對字符編碼,用來制定傳輸數據的特殊類型,如mp3、jpg |
text/plain | 純文本傳輸 |
因此,傳輸完整的文件數據需要multipart/form-data
屬性。
Input
value
保存了用戶指定的文件的名稱。
type="file"
設置input類型為file。
multiple="multiple"
可多選,不設置為單選。
accept="..."
設置可選文件的MIME_type。在設置之后點擊選擇文件按鈕會默認顯示符合設置的MIME_type的文件(存在兼容性)。具體的文件類型對應的MIME類型可以搜索到,這里列出我用到的類型:
文件類型 | MIME類型 |
---|---|
.txt | text/plain |
application/pdf | |
.doc | application/msword |
.docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document |
.xls | application/vnd.ms-excel |
.ppt | application/vnd.ms-powerpoint |
.pptx | application/vnd.openxmlformats-officedocument.presentationml.presentation |
效果
太丑,不能忍...
CSS
默認界面會在選擇文件按鈕后會跟一個顯示文件名的文本區域,選擇文件按鈕無法編輯。 我修改的方法是將input框隱藏,再設置一個lable標簽使用戶點擊lable標簽時觸發選擇文件按鈕。
<label for="file">選擇文件</label>
復制代碼
效果
JS
在使用from提交時,瀏覽器會向服務器發送選中的文件的內容而不僅僅是發送文件名。
為安全起見,
<input type="file">
即file-upload 元素不允許 HTML 作者或 JavaScript 程序員指定一個默認的文件名。HTML value 屬性被忽略,并且對于此類元素來說,value屬性是只讀的,這意味著只有用戶可以輸入一個文件名。當用戶選擇或編輯一個文件名時,file-upload 元素觸發 onchange 事件句柄。
利用form提交會導致頁面刷新,體驗不好,所以使用AJAX進行文件上傳是個不錯的選擇。但這需要我們自己來組織通過POST請求發送的內容。
FormData對象
通過FormData對象可以組裝一組用 XMLHttpRequest發送請求的鍵/值對。它可以更靈活方便的發送表單數據,因為可以獨立于表單使用。如果你把表單的編碼類型設置為multipart/form-data ,則通過FormData傳輸的數據格式和表單通過submit() 方法傳輸的數據格式相同。 —— MDN web docs
創建FormData對象
let formData = new FormData();
復制代碼
向實例化對象中添加文件字段
let myFile = document.getElementById('file');
// myFile.file[0]為第一個文件(單選),多個文件(多選)則要循環添加
formData.append('myFile', myFile.files[0]);
復制代碼
console.log(myFile.files[0]);
復制代碼
其中size屬性單位是byte(字節),即b。
添加自定義字段
formData.append('username', 'simmzl');
復制代碼
AJAX發送
let request = new XMLHttpRequest();
request.open("POST", "http://foo.com/foo.php");
request.send(formData);
復制代碼
不使用FromData對象
不使用FormData對象的情況下,需要通過AJAX序列化和提交表單 : Using nothing but XMLHttpRequest
PHP
接收
全局數組 $_FILES
,第一個參數是表單的 input name,第二個下標是 "name", "type", "size", "tmp_name" 或 "error"。可以根據這些屬性做相關限制,如限制文件大小、文件類型等。
值 | 描述 |
---|---|
name | 文件名 |
type | 文件的MIME類型 |
size | 以字節Byte為單位的文件大小 |
tmp_name | PHP接收文件會存為暫時文件,如需保存到指定路徑還要移動這個暫時文件才可以 |
error | 1-7 代表7種不同錯誤類別以及0 代表成功 |
error: 成功:0(UPLOAD_ERR_OK) 失敗:
- 超過了配置文件上傳文件的大小
- 超過了表單設置上傳文件的大小
- 文件部分被上傳
- 沒有文件被上傳
- 沒有找到臨時目錄
- 文件不可寫
- 由于PHP的擴展程序中斷了文件上傳
驗證
上傳文件是通過POST發送的,is_uploaded_file(file)
函數可以判斷指定的文件是否是通過 HTTP POST 上傳的,返回布爾值。
該函數可以用于確保惡意的用戶無法欺騙腳本去訪問本不能訪問的文件,例如 /etc/passwd。 這種檢查顯得格外重要,如果上傳的文件有可能會造成對用戶或本系統的其他用戶顯示其內容的話。
保存
上傳的文件暫存在tmp_name中,需要使用move_uploaded_file(file,newlocation)
將上傳的文件移動到指定路徑,返回布爾值。
if( move_uploaded_file($tmp_name, $destination) ) {echo "文件上傳成功";
}else{echo "文件移動失敗";
}
復制代碼
刪除
使用unlink(filepath)
刪除文件,參數是文件路徑。
拓展功能
當然除了接收、驗證、保存和刪除這四個基本操作外,還可以添加諸如將文件路徑存入數據庫、生成文件列表等功能,視需求而定。
最初發表于blog.simmzl.cn