FireFox瀏覽器使用Javascript上傳大文件
本程序是利用3.x的Firefox瀏覽器可以讀取本地文件的特性,實(shí)現(xiàn)通過xmlHttPRequest上傳大文件功能,并在可以上傳過程中動(dòng)態(tài)顯示上傳進(jìn)度。略加修改,并與服務(wù)器端配合,可以實(shí)現(xiàn)斷點(diǎn)續(xù)傳等諸多功能。
本例主要是研究FireFox的file-input節(jié)點(diǎn)的一些特性,其他客戶端應(yīng)用,如Flash、Sliverlight等,在實(shí)現(xiàn)客戶端大文件上傳時(shí),在數(shù)據(jù)傳輸與服務(wù)器端存儲(chǔ)等方面,與本例的思路基本一致。
注意:文件體積似乎有臨界點(diǎn),但這個(gè)臨界點(diǎn)是多少尚未確認(rèn)。建議不要用此方法上傳超過100M的文件。
以下是客戶端javascript代碼
/*
* FireFoxFileSender version 0.0.0.1
* by MK winnie_mk(a)126.com
*
* 【本程序僅限于FireFox3.x版本,其他瀏覽器是否可以運(yùn)行未做測(cè)試?!?br /> * 【測(cè)試通過:FireFox 3.6.8 / Apache/2.2.11 (Win32) php/5.2.6 】
* ******************************************************************************
* 本程序是利用3.x的FireFox瀏覽器可以讀取本地文件的特性
* 實(shí)現(xiàn)通過xmlhttpRequest上傳大文件功能
* 并在可以上傳過程中動(dòng)態(tài)顯示上傳進(jìn)度
* 略加修改,并與服務(wù)器端配合,可以實(shí)現(xiàn)斷點(diǎn)續(xù)傳等諸多功能
* 本例主要是研究FireFox的file-input節(jié)點(diǎn)的一些特性
* 其他客戶端應(yīng)用,如Flash、Sliverlight等,在實(shí)現(xiàn)客戶端大文件上傳時(shí)
* 在數(shù)據(jù)傳輸與服務(wù)器端存儲(chǔ)等方面,與本例的思路基本一致
* 注意:文件體積似乎有個(gè)臨界點(diǎn),但這個(gè)臨界點(diǎn)是多少尚未確認(rèn)。建議不要用此方法上傳超過100M的文件。
* ******************************************************************************
*/
function FireFoxFileSender(config){
var conf = config || {};
/*
* 錯(cuò)誤信息隊(duì)列
*/
this.errMsg = [];
/*
* 判斷各參數(shù)是否齊備
*/
this.f = typeof conf.file == 'string' ?
document.getElementById(conf.file) : conf.file;
if(!this.f){ this.errMsg.push('Error: Not set the input file.'); }
else if(this.f.files.length < 1){ this.errMsg.push('Error: Not select a file.'); }
else {
this.fileName = this.f.value;
/*
* 在嘗試直接發(fā)送二進(jìn)制流時(shí)失敗,改用發(fā)送base64編碼數(shù)據(jù)。
*/
this.data = (this.data = this.f.files[0].getAsDataURL())
.substr(this.data.indexOf(',') + 1);
this.length = this.data.length;
/*
* 文件實(shí)際大小
*/
this.fileSize = this.f.files[0].fileSize;
/*
* 文件類型
*/
this.contentType = this.f.files[0].fileType;
}
/*
* 服務(wù)器端接收地址
*/
this.url = conf.url;
if(!this.url){
this.errMsg.push('Error: Not set the instance url to send binary.');
}
/*
* 發(fā)送數(shù)據(jù)包的大小。默認(rèn)100kb
*/
this.packageSize = conf.packageSize || 102400;
/*
* 每次發(fā)送數(shù)據(jù)包大小應(yīng)為4的倍數(shù),確保服務(wù)器端轉(zhuǎn)換base64編碼正確。
*/
if(this.packageSize % 4 != 0)
this.packageSize = parseInt(this.packageSize / 4) * 4;
this.onSendFinished = conf.onSendFinished || null;
this.onSending = conf.onSending || null;
this.onError = conf.onError || null;
}
FireFoxFileSender.prototype = {
/*
* 記錄當(dāng)前發(fā)送的數(shù)據(jù)
*/
currentData : null,
/*
* 記錄讀取位置
*/
position : 0,
/*
* 數(shù)據(jù)大小。該值為base64字符串的長(zhǎng)度。
*/
length : -1,
/*
* 檢查錯(cuò)誤隊(duì)列,嘗試觸發(fā)onError事件
*/
checkError : function(){
if(this.errMsg.length > 0){
/*
* 觸發(fā)onError事件
*/
typeof this.onError == 'function' && this.onError(this.errMsg);
return;
}
},
/*
* 創(chuàng)建XMLHttpRequest
*/
createSender : function(){
var xhr = new XMLHttpRequest();
xhr.open('POST', this.url, true);
var _ = this;
xhr.onreadystatechange = function(){
/*
* 當(dāng)服務(wù)器段響應(yīng)正常,則循環(huán)讀取發(fā)送。
*/
if(xhr.readyState == 4 && xhr.status == 200){
/*
* 觸發(fā)onSending事件
*/
if(typeof _.onSending == 'function') _.onSending(_, xhr);
/*
* 延時(shí)發(fā)送下一次請(qǐng)求,否則服務(wù)器負(fù)擔(dān)過重
*/
var send = setTimeout(function(){
_.send();
clearTimeout(send);
send = null;
}, 100);
}
}
return xhr;
},
/*
* 發(fā)送數(shù)據(jù)
*/
send : function(){
this.checkError();
/*
* 獲取當(dāng)前要發(fā)送的數(shù)據(jù)
*/
this.currentData = this.data.substr(this.position, this.packageSize);
/*
* 更改postion,模擬數(shù)據(jù)流移位
*/
this.position += this.currentData.length;
/*
* 如果讀取字符串長(zhǎng)度大于0,則發(fā)送該數(shù)據(jù)
* 否則觸發(fā)onSendFinished事件
*/
if(this.currentData.length > 0) {
var xhr = this.createSender();
/*
* 自定義頭部信息,通知服務(wù)器端文件相關(guān)信息
* 實(shí)際應(yīng)用時(shí)可修改此部分。
*/
xhr.setRequestHeader('#FILE_NAME#', this.fileName);
xhr.setRequestHeader('#FILE_SIZE#', this.length);
xhr.setRequestHeader('#CONTENT_TYPE#', this.contentType);
xhr.send(this.currentData);
} else if(typeof this.onSendFinished == 'function') {
/*
* 觸發(fā)onSendFinished事件
*/
this.onSendFinished(this);
}
},
/*
* 計(jì)算已發(fā)送數(shù)據(jù)百分比
*/
percent : function(){
if(this.length <= 0 ) return -1;
return Math.round((this.position / this.length) * 10000) / 100;
},
onSendFinished : null, //該事件是以本地?cái)?shù)據(jù)發(fā)送完成為觸發(fā),并不是服務(wù)器端返回的完成信息。
onSending : null,
onError : null
}
/*
* 上傳按鈕事件
*/
function send(fileID){
var sender = new FireFoxFileSender(
/*
* 上傳配置文件
*/
{
/*
* input file 元素,可以是dom節(jié)點(diǎn),也可以是id的字符串值
*/
file : fileID,
/*
* 接收上傳數(shù)據(jù)的服務(wù)器端地址
*/
url : 'UPLOADER.php',
/*
* 每次發(fā)送數(shù)據(jù)包的大小。可根據(jù)服務(wù)器具體情況更改。IIS6默認(rèn)為200K
*/
packageSize : '200000',
/*
* 出現(xiàn)錯(cuò)誤時(shí)觸發(fā)該事件。本例僅在初始化時(shí)判斷各參數(shù)是否齊備,并沒有拋出發(fā)送過程中的錯(cuò)誤。
*/
onError : function(arrMsg){
alert(arrMsg.join('\r\n'));
sender = null;
delete sender;
},
/*
* 發(fā)送過程中觸發(fā)該事件。本例中主要用于顯示進(jìn)度。
*/
onSending : function(sd, xhr){
var per = sd.percent();
document.getElementById('Message').innerHTML = per + '% ';
/*
* 該判斷是在最后一次發(fā)送結(jié)束后,通過xhr的onreadystatechange事件觸發(fā)的
* 如果傳輸過程中沒有其他錯(cuò)誤,基本可以確定為服務(wù)器端接收完成
*/
if(parseInt(per) == 100){ alert('服務(wù)器端接收完成'); }
},
/*
* 該事件僅僅為【本地?cái)?shù)據(jù)發(fā)送完成】時(shí)觸發(fā)。
* 請(qǐng)區(qū)別本地?cái)?shù)據(jù)發(fā)送完成和服務(wù)器端返回完成信息這兩種情況
* 本例中并沒有對(duì)服務(wù)器接收信息的情況做響應(yīng)
* 即使服務(wù)器端沒有接收和保存任何數(shù)據(jù)
* 只要確保xhr返回readyState == 4 和 status == 200
* 發(fā)送就會(huì)繼續(xù)進(jìn)行
* 服務(wù)器端如何返回完成信息可以通過更改接收數(shù)據(jù)頁面的代碼自定實(shí)現(xiàn)
* 然后通過對(duì)xhr.responseText的值來做判斷
*/
onSendFinished : function(){
alert('本地?cái)?shù)據(jù)發(fā)送完成');
}
}
);
sender.send();
}
以下是服務(wù)器端php代碼
/*
* 獲取輸入信息
*/
$b64 = file_get_contents("php://input");
/*
* 獲取頭部信息
*/
$headers = getallheaders();
$fileName = $headers['#FILE_NAME#'];
$contentType = $headers['#CONTENT_TYPE#'];
/*
* 做一些判斷和處理...
*/
/*
* 以下是服務(wù)器端對(duì)發(fā)送數(shù)據(jù)的簡(jiǎn)單響應(yīng)
* - 假如有數(shù)據(jù)被post過來 則輸出對(duì)base64轉(zhuǎn)換為二進(jìn)制流后,二進(jìn)制流的長(zhǎng)度
* - 否則輸出0
* 這僅僅是一個(gè)例子,并且在js端沒有接收這個(gè)信息
* 同樣,也可以采用在header中寫入反饋信息等等方法
* 回饋信息給客戶端
* 主要目的是確定上傳過程中是否有其他問題出現(xiàn)
* 以確保上傳文件完整
*/
if(!empty($b64)){
$stream = base64_decode($b64);
echo strlen($stream);
/*
* 追加方式寫入文件
* 在此修改文件保存位置
*/
$file = fopen('' . $fileName , 'a');
if($file)
if(fwrite($file, $stream))
fclose($file);
} else echo '0';
客戶端完整代碼
<!DOCTYPE HTML>
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5 <title>FireFoxFileSender - !! ONLY FOR FireFox !!</title>
6 </head>
7
8 <body>
9 <script type="text/Javascript">
10 /*
11 * FireFoxFileSender version 0.0.0.1
12 * by MK winnie_mk(a)126.com
13 *
14 * 【本程序僅限于FireFox3.x版本,其他瀏覽器是否可以運(yùn)行未做測(cè)試?!?br /> 15 * 【測(cè)試通過:FireFox 3.6.8 / Apache/2.2.11 (Win32) PHP/5.2.6 】
16 * *********************************************************************************
17 * 本程序是利用3.x的FireFox瀏覽器可以讀取本地文件的特性
18 * 實(shí)現(xiàn)通過XMLHttpRequest上傳大文件功能
19 * 并在可以上傳過程中動(dòng)態(tài)顯示上傳進(jìn)度
20 * 略加修改,并與服務(wù)器端配合,可以實(shí)現(xiàn)斷點(diǎn)續(xù)傳等諸多功能
21 * 本例主要是研究FireFox的file-input節(jié)點(diǎn)的一些特性
22 * 其他客戶端應(yīng)用,如Flash、Sliverlight等,在實(shí)現(xiàn)客戶端大文件上傳時(shí)
23 * 在數(shù)據(jù)傳輸與服務(wù)器端存儲(chǔ)等方面,與本例的思路基本一致
24 * 注意:文件體積似乎有個(gè)臨界點(diǎn),但這個(gè)臨界點(diǎn)是多少尚未確認(rèn)。建議不要用此方法上傳超過100M的文件。
25 * *********************************************************************************
26 */
27 function FireFoxFileSender(config){
28 var conf = config || {};
29 /*
30 * 錯(cuò)誤信息隊(duì)列
31 */
32 this.errMsg = [];
33 /*
34 * 判斷各參數(shù)是否齊備
35 */
36 this.f = typeof conf.file == 'string' ? document.getElementById(conf.file) : conf.file;
37 if(!this.f){ this.errMsg.push('Error: Not set the input file.'); }
38 else if(this.f.files.length < 1){ this.errMsg.push('Error: Not select a file.'); }
39 else {
40 this.fileName = this.f.value;
41 /*
42 * 在嘗試直接發(fā)送二進(jìn)制流時(shí)失敗,改用發(fā)送base64編碼數(shù)據(jù)。
43 */
44 this.data = (this.data = this.f.files[0].getAsDataURL()).substr(this.data.indexOf(',') + 1);
45 this.length = this.data.length;
46 /*
47 * 文件實(shí)際大小
48 */
49 this.fileSize = this.f.files[0].fileSize;
50 /*
51 * 文件類型
52 */
53 this.contentType = this.f.files[0].fileType;
54 }
55 /*
56 * 服務(wù)器端接收地址
57 */
58 this.url = conf.url;
59 if(!this.url){ this.errMsg.push('Error: Not set the instance url to send binary.'); }
60 /*
61 * 發(fā)送數(shù)據(jù)包的大小。默認(rèn)100kb
62 */
63 this.packageSize = conf.packageSize || 102400;
64 /*
65 * 每次發(fā)送數(shù)據(jù)包大小應(yīng)為4的倍數(shù),確保服務(wù)器端轉(zhuǎn)換base64編碼正確。
66 */
67 if(this.packageSize % 4 != 0) this.packageSize = parseInt(this.packageSize / 4) * 4;
68
69 this.onSendFinished = conf.onSendFinished || null;
70 this.onSending = conf.onSending || null;
71 this.onError = conf.onError || null;
72 }
73 FireFoxFileSender.prototype = {
74 /*
75 * 記錄當(dāng)前發(fā)送的數(shù)據(jù)
76 */
77 currentData : null,
78 /*
79 * 記錄讀取位置
80 */
81 position : 0,
82 /*
83 * 數(shù)據(jù)大小。該值為base64字符串的長(zhǎng)度。
84 */
85 length : -1,
86 /*
87 * 檢查錯(cuò)誤隊(duì)列,嘗試觸發(fā)onError事件
88 */
89 checkError : function(){
90 if(this.errMsg.length > 0){
91 /*
92 * 觸發(fā)onError事件
93 */
94 typeof this.onError == 'function' && this.onError(this.errMsg);
95 return;
96 }
97 },
98 /*
99 * 創(chuàng)建XMLHttpRequest
100 */
101 createSender : function(){
102 var xhr = new XMLHttpRequest();
103 xhr.open('POST', this.url, true);
104 var _ = this;
105 xhr.onreadystatechange = function(){
106 /*
107 * 當(dāng)服務(wù)器段響應(yīng)正常,則循環(huán)讀取發(fā)送。
108 */
109 if(xhr.readyState == 4 && xhr.status == 200){
110 /*
111 * 觸發(fā)onSending事件
112 */
113 if(typeof _.onSending == 'function') _.onSending(_, xhr);
114 /*
115 * 延時(shí)發(fā)送下一次請(qǐng)求,否則服務(wù)器負(fù)擔(dān)過重
116 */
117 var send = setTimeout(function(){
118 _.send();
119 clearTimeout(send);
120 send = null;
121 }, 100);
122 }
123 }
124 return xhr;
125 },
126 /*
127 * 發(fā)送數(shù)據(jù)
128 */
129 send : function(){
130 this.checkError();
131 /*
132 * 獲取當(dāng)前要發(fā)送的數(shù)據(jù)
133 */
134 this.currentData = this.data.substr(this.position, this.packageSize);
135 /*
136 * 更改postion,模擬數(shù)據(jù)流移位
137 */
138 this.position += this.currentData.length;
139 /*
140 * 如果讀取字符串長(zhǎng)度大于0,則發(fā)送該數(shù)據(jù)
141 * 否則觸發(fā)onSendFinished事件
142 */
143 if(this.currentData.length > 0) {
144 var xhr = this.createSender();
145 /*
146 * 自定義頭部信息,通知服務(wù)器端文件相關(guān)信息
147 * 實(shí)際應(yīng)用時(shí)可修改此部分。
148 */
149 xhr.setRequestHeader('#FILE_NAME#', this.fileName);
150 xhr.setRequestHeader('#FILE_SIZE#', this.length);
151 xhr.setRequestHeader('#CONTENT_TYPE#', this.contentType);
152
153 xhr.send(this.currentData);
154 } else if(typeof this.onSendFinished == 'function') {
155 /*
156 * 觸發(fā)onSendFinished事件
157 */
158 this.onSendFinished(this);
159 }
160 },
161 /*
162 * 計(jì)算已發(fā)送數(shù)據(jù)百分比
163 */
164 percent : function(){
165 if(this.length <= 0 ) return -1;
166 return Math.round((this.position / this.length) * 10000) / 100;
167 },
168 onSendFinished : null, //該事件是以本地?cái)?shù)據(jù)發(fā)送完成為觸發(fā),并不是服務(wù)器端返回的完成信息。
169 onSending : null,
170 onError : null
171 }
172
173 /*
174 * 上傳按鈕事件
175 */
176 function%3
相關(guān)文章
ThinkPHP實(shí)現(xiàn)多數(shù)據(jù)庫連接的解決方法
這篇文章主要介紹了ThinkPHP實(shí)現(xiàn)多數(shù)據(jù)庫連接的解決方法,需要的朋友可以參考下2014-07-07ThinkPHP采用<volist>實(shí)現(xiàn)三級(jí)循環(huán)代碼實(shí)例
這篇文章主要介紹了ThinkPHP采用<volist>實(shí)現(xiàn)三級(jí)循環(huán)代碼實(shí)例,通過實(shí)例加深讀者對(duì)<volist>標(biāo)簽用法的認(rèn)識(shí),需要的朋友可以參考下2014-07-07php獲取本年、本月、本周時(shí)間戳和日期格式的實(shí)例代碼
這篇文章主要介紹了php獲取本年、本月、本周時(shí)間戳和日期格式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01Laravel基礎(chǔ)-關(guān)于引入公共文件的兩種方式
今天小編就為大家分享一篇Laravel基礎(chǔ)-關(guān)于引入公共文件的兩種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-10-10PHP開發(fā)框架kohana3 自定義路由設(shè)置示例
這篇文章主要介紹了PHP開發(fā)框架kohana3 自定義路由設(shè)置示例,kohana是一個(gè)純PHP5的開發(fā)框架,需要的朋友可以參考下2014-07-07