在PHP5.4以前, 我們可以通過APC提供的功能來實現. 或者使用PECL擴展uploadprogress來實現.
雖然說, 它們能很好的解決現在的問題, 但是也有很明顯的不足:
- 1. 他們都需要額外安裝(我們並沒有打算把APC加入PHP5.4)
- 2. 它們都使用本地機制來存儲這些信息, APC使用共享內存, 而uploadprogress使用文件系統(不考慮NFS), 這在多台前端機的時候會造成麻煩.
程序需要php的apc模塊的支持,關鍵點就是在上傳的form里添加一個hidden的inpu標簽,里面要有name為
APC_UPLOAD_PROGRESS的屬性,value值為一個隨機數一遍多個人上傳。
apc模塊的安裝方法是,下載php_apc.dll放到ext文件夾下,在php.ini文件里添加
upload_max_filesize =100M
apc.rfc1867 = on
apc.max_file_size = 100M
extension=php_apc.dll
然后測試配置是否成功:
if(apc_fetch)
{echo "apc is working"}
else{echo "apc is not supported!";}
運行效果截圖

下面是源碼
1 前台頁面:
- <html>
- <title>PHP+Ajax帶進度條文件上傳</title>
- <head>
- <style type="text/css">
- #progress{
- border:2px red solid;
- width:200px;
- height:20px;
- display:none;
- }
- #pecent{
- background-color:green;
- display:block;
- width:0px;
- height:20px;
- color:yellow;
- }
- </style>
- </head>
- <body>
- <iframe style="display:none" name="ifm"></iframe>
- <form enctype="multipart/form-data" method="POST" action="upload.php" target="ifm" name="myform">
- <input type="hidden" name="APC_UPLOAD_PROGRESS" id="remark" >
- <input type="file" name="upfile"/>
- <input type="submit" value="上傳" name="sub"/>
- </form>
- <div id="progress" class="before"><span id="pecent"></span></div>
- <script type="text/javascript">
- (function(){
- function addEvent( node, type, listener ) {
- if (node.addEventListener) {
- // W3C method
- node.addEventListener( type, listener, false );
- return true;
- } else if(node.attachEvent) {
- // MSIE method
- node['e'+type+listener] = listener;
- node[type+listener] = function(){node['e'+type+listener]( window.event );}
- node.attachEvent( 'on'+type, node[type+listener] );
- return true;
- }
- // Didn't have either so return false
- return false;
- };
- var submit=document.forms["myform"];
- addEvent(submit,'submit',startUpload);
- var begin;
- var request;
- var rdm;
- var pec=document.getElementById("pecent");
- function startUpload()
- {
- rdm=Math.floor(Math.random()*100000000);
- document.getElementById('remark').setAttribute('value',rdm);
- document.getElementById("progress").style['display']='block';
- //creatXmlHttpRequest();
- begin=setTimeout(doRequest,1000);
- };
- function creatXmlHttpRequest()
- {
- if(window.ActiveXObject)
- {request=new ActiveXObject("Microsoft.XMLHTTP")}
- else{request=new XMLHttpRequest();}
- };
- var count=0;
- function doRequest()
- {
- if(window.ActiveXObject)
- {request=new ActiveXObject("Microsoft.XMLHTTP");}
- else{request=new XMLHttpRequest();}
- if(request!=null){
- request.onreadystatechange=handle;
- request.open("GET","upload.php?key="+rdm+"&sim=" + (++count),true);
- request.send();
- }
- };
- function handle()
- {
- if(request.readyState==4&&request.status==200)
- {
- //接受服務器數據
- var prgs=eval("(" + request.responseText + ")");
- //var prgs=request.responseText;
- var cur=parseInt(prgs.current);
- var total=parseInt(prgs.total);
- var pecentIs=Math.round(cur/total*100);
- pec.innerHTML=pecentIs.toString()+"%";
- if(100==pecentIs)
- {
- pec.style['width']="200px";
- clearTimeout(begin);
- }else{
- begin=setTimeout(doRequest,1000);
- //alert(pecentIs);
- pec.style['width']=pecentIs*2;
- }
- }
- };
- })();
- </script>
- </body>
- </html>
2后台upload.php文件代碼:
- <?php
- /*
- * Created on 2010-4-16
- *
- * To change the template for this generated file go to
- * Window - Preferences - PHPeclipse - PHP - Code Templates
- */
- if ($_SERVER['REQUEST_METHOD'] == 'POST'){
- $myfile=$_FILES['upfile'];
- echo $myfile['size'];
- echo $myfile['size'];
- print_r($myfile);
- $tempf=$myfile['tmp_name'];
- $name=$myfile['name'];
- move_uploaded_file($tempf,'up/'.$name);}
- if(isset($_GET['key']))
- {
- //header('Content-Type:application/json; charset=utf-8' ) ;
- // Retrieve the status using the getStatus() function below
- //echo json_encode(getStatusAPC());
- echo json_encode(getStatusAPC());
- }
- function getStatusAPC()
- {
- $response=false;
- if($status = apc_fetch('upload_'.$_GET['key'])) {
- $response=apc_fetch('upload_'.$_GET['key']);
- }
- return $response;
- }
- ?>
問題總結:
1,使用setTimeout嵌套和setInterval有區別,用前者效果較好,用后者的話由於請求和返回的時間比較隨機,時間間隔把握不好的話,程序會比較混亂,結果往往不正確。
2.發送Ajax請求時每次都要重新實例化xmlhttprequest對象而不能用上次實例化的,否則程序在ie下無法執行,在火狐下可以運行

