一直困擾著Web開發人員多年的一個問題是如何即時資訊添加到自己的應用程序,例如文件上傳進度條。 用戶沒有耐心,他們不想坐等,而瀏覽器是做什麼,不知是否已凍結或者,如果他們有一個緩慢的連接。 提供了一個進度指示器為使用者提供有用的信息,並讓他們知道到底發生了什麼事情。
在第一個想到的,你可能會認為完成這可以很容易地通過首先獲得從用戶的計算機中的文件的大小,然後進行一些簡單的計算對目錄下的文件被上傳到伺服器上完成。 關於第二個想法,你會發現事情並沒有想像中的那麼簡單。
JavaScript可以存取一個檔案的名稱,類型,甚至寬度和本機映像的高度,但它不是直到HTML5,它可以存取一個檔案的大小 。 不幸的是,HTML5仍然是一個沒有完成的標準還沒有,而不是統一在所有瀏覽器都支援。另一個解決方案是依靠一個Flash,Java或安裝ActiveX插件,不,謝謝,我會通過。 另一個解決方案是安裝可選PHP快取擴展,但根據您的託管環境中可能無法使用,這似乎有點小題大做,這樣一個小任務,例如這個。
這似乎就像所有的選項都充滿了滋擾,任務已經迅速成為一個頭痛的問題。 但在尤達的話來說,「沒有......還有一個。」
其中的原因有很多我喜歡PHP的是,它使看似困難的任務很容易。 在PHP 5.4中,他們已經再次使用一組新的設定選項,做到了session.upload_progress 。
在本文中,我將向您展示如何這個功能可以被用來創建一個簡單的上傳進度條沒有任何外部庫或瀏覽器的依賴。 我會先討論它是如何運作的,然後我會引導您完成建立完成的任務(一個上傳表單,一些JavaScript,一點點CSS和檔案回傳載的狀態)所需的四個檔案。
會議上傳進度
除了通常的要求,以允許文件上傳,還有兩個來追蹤進度。 該session.upload_progress.enabled指令必須啟用,並且必須有一個隱藏欄位中的Web表單與指定的名稱session.upload_progress.name指令。當session.upload_progress.enabled是真的(因為它是在預設情況下在PHP 5.4及想必以後)和$_POST[session.upload_progress.name ]中關於檔案的傳輸上載,訊息傳送是可用的$_SESSION超全域數組。
該print_r()輸出的$_SESSION數組看起來類似於下面的一個文件傳輸過程中:
排列 ( [upload_progress_myForm] =>陣列 ( [T_TIME] => 1323733740 ( [T_TIME] => 1323733740 1 ed] = > 263178326 [完成] => [檔案] =>陣列 ( [0] =>陣列 ( [FIELD_NAME] => USERFILE [姓名] =>的ubuntu-10.04.3-桌面i386.iso name] =>的ubuntu-10.04.3-桌面i386.iso 的值[錯誤] => 0 [完成] => [START_TIME] => 1323733740 [bytes_processed] => 263178026 ) ) ) [START_TIME] => 1323733740 [bytes_processed] => 263178026 ) ) ) )
<?PHP 如果($ _SERVER [ “REQUEST_METHOD” ] == “POST” &&!空($ _FILES [ “userfile的” ])){ / / move_uploaded_file()以 } ?> <HTML> <HEAD> <TITLE>文件上传进度条</ TITLE> <链接相对= “样式表” 类型= “文/ CSS” HREF = “style.css文件” > </ HEAD> <BODY> <分区编号= “bar_blank” > <分区编号= “bar_color” > </ DIV> </ DIV> <分区编号= “状态” > </ DIV> <形式的行动= “<PHP的回声$ _SERVER?[” PHP_SELF “];?>” 方法= “POST” ID = “myForm的” 是enctype = “多部分/窗体的数据” 目标= “hidden_iframe” > <输入类型= “隐藏” 值= “myForm的” 名称= “<?PHP的回声ini_get(” session.upload_progress.name ?“);>” > <输入类型= “文件” 名称= “USERFILE” > <BR> <输入类型= “提交” 值= “开始上传” > </ FORM> <iframe的ID = “hidden_iframe” 名称= “hidden_iframe” SRC = “关于:空白” > </ IFRAME> <脚本类型= “文/ JavaScript的” SRC = “的script.js” > </ SCRIPT> </ BODY> </ HTML>
该窗体设置为提交给同一个URL,并将其目标属性指向一个隐藏的iframe元素。 提交表单到一个隐藏的框架可以让你保持访问者在同一页上,而工作在后台正在做。 其实,这是一种常见的做法做“的Ajax文件上传”的时候,因为它是不可能直接发送使用JavaScript的一个文件的内容XmlHttpRequest对象。
在表格中,特殊的隐藏字段需要填充$_SESSION数组,接着出现一个文件上传输入和提交按钮。 提交表单将触发一个名为JavaScript函数startUpload()将被包含的JavaScript文件中定义。
在页面的底部是隐藏的框架,其形式将发布和进口script.js文件。
添加一些样式
下一个文件, style.css ,是相当直接的。 我定义的进度条容器的大小并给予它一个1px的黑色边框,进度条的颜色,因为它的加载,无论是IFRAME和进度条是隐藏的。
#bar_blank { 边界:固体1px的#000 ; 高度:20像素; 宽度:300像素; } #bar_color { 背景色:#006666 ; 高度:20像素; 宽度:0PX ; } #bar_blank,#hidden_iframe { 显示:无; }
客户端功能
该script.js文件是最大的组文件。 它包含六大功能,我将在下面讨论。 很多人喜欢用jQuery来提供一些功能在这里,你当然可以这样做,如果你愿意的话,但我个人更喜欢老派的做法。 类似于如何日本人放在手工制作的货物价值较高的,我只是觉得更热衷于代码,如果是我自己。
功能toggleBarVisibility(){ 变种E =的document.getElementById(“bar_blank” ); e.style.display =(e.style.display == “块” ?) “ 无” :“块” ; } 功能createRequestObject(){ 变种的http; 如果(navigator.appName == “Microsoft Internet Explorer的” ){ HTTP = 新的ActiveXObject(“Microsoft.XMLHTTP” ); } 否则{ HTTP = 新的XMLHttpRequest(); } 返回的http; } 功能sendRequest将(){ 变种的http = createRequestObject(); http.open(“GET” ,“progress.php” ); http.onreadystatechange = 函数(){用handleResponse(HTTP);}; http.send(空); } 功能用handleResponse(HTTP){ 无功响应; 如果(http.readyState == 4){ 响应= http.responseText; 的document.getElementById(“bar_color” 。)共0则回应+ “%” ; 的document.getElementById( “ 地位” 。)的innerHTML =响应+ “%” ; 如果(响应<100){ 的setTimeout(“sendRequest将()” ,1000); } 否则{ toggleBarVisibility(); 的document.getElementById( “ 地位” 。)的innerHTML = “Done(完成)。” ; } } } 功能startUpload(){ toggleBarVisibility(); 的setTimeout(“sendRequest将()” ,1000); } (函数(){ 的document.getElementById(“myForm会” )的onsubmit = startUpload; })();
该toggleBarVisibility()函数上的“bar_blank”的div根据需要显示或隐藏进度条设置合适的样式。 最初,它开始时隐藏,但会一次上传开始出现,然后再次隐藏当上载完成。
该createRequestObject()函数创建一个XMLHttpRequest或ActiveXObject根据用户的浏览器对象。 这可能是该功能大多数人都期待的jQuery或其他一些JavaScript框架来提供。
该sendRequest()函数请求progress.php文件与一个GET请求,然后调用handleResponse()函数来处理返回的数据。
该handleResponse()函数处理从响应progress.php这将是依赖于文件上传进度多项1-100之间。 我也更新了“状态”的div适当的值。 如果电流的百分比低于100然后调用JavaScript的原生setTimeout()函数来1秒后发送的更新另一个请求(你可能需要调整该值如适用),否则我再次隐藏进度条和状态设置为“完成”。
该startUpload()函数使得载栏可见,并发送一个更新请求的1秒的延迟。 这个小的延迟是必要的,为了给上传时间才能启动。
最后一个功能是一个自执行的匿名函数,它注册startUpload()与表单的提交事件。
实时进展
带来一切融合在一起的最后一个文件是progress.php文件:
<?PHP 在session_start(); 美元的关键= ini_get (“session.upload_progress.prefix” )。“myForm的” ; 如果(!空($ _SESSION [ $关键])){ $电流= $ _SESSION [ $关键] [ “bytes_processed” ]; 共$ = $ _SESSION [ $关键] [ “CONTENT_LENGTH” ]; 回声$电流< $总?CEIL ($电流/ $总量* 100):100; } 否则{ 回声100; }
该脚本执行上传输的字节数目前在总文件大小,再乘以100,并四舍五入到给一个百分比分成一些简单的数学。
有关传输的信息,关键在于有一套与session.upload_progress.prefix指令的值的串联和隐藏session.upload_progress.name字段的值。 因为我的形式通过了“myForm会”,会议的重点是与确定ini_get("session.upload_progress.prefix") . "myForm"ini_get("session.upload_progress.prefix") . "myForm" 。
下面是在行动进度条的截图:
微调行为
PHP提供了一些额外的指令来帮助微调会话上传的行为,你应该知道的。 例如,session.upload_progress.cleanup ,这是默认设置为1,清理后,立即上传已经完成了额外的会话数据。 你必须要小心,以避免潜在的竞争条件。
再看看在代码progress.php ,你会发现,我检查,看看是否$_SESSION[$key]为空或不是,然后再继续。我的JavaScript函数火了每一秒,只要结果从返回progress.php小于100。 如果session.upload_progress.cleanup已启用,我的脚本获取99%的上传和1/2-second后上传完成后,$_SESSION[$key]不会为下一个检查存在的。 如果我不考虑到这一点,然后我的JavaScript函数可能保持射击,上传完成之后也是如此。
另外兩個指令是session.upload_progress.freq和session.upload_progress.min_freq這兩個決定多久了會議要更新。 頻率的值可以在任一位元組(即100)或總位元組數的百分比(即2%)給出。 價值min_freq以秒為單位,並表示更新之間的最小秒數。 顯然,如果min_freq設定為更新每隔1秒,這將是毫無意義的JavaScript來檢查每100毫秒。
總結
你現在應該有一個牢固掌握如何創建使用會話上傳進度功能的文件上傳進度條。 展望未來,我鼓勵你嘗試上傳多個文件,給予取消使用上傳進行中的選項$_SESSION[$key]["cancel_upload"] ,或任何其他的想法你的思想可以鼓起。