在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>
- <styletype="text/css">
- #progress{
- border:2pxredsolid;
- width:200px;
- height:20px;
- display:none;
- }
- #pecent{
- background-color:green;
- display:block;
- width:0px;
- height:20px;
- color:yellow;
- }
- </style>
- </head>
- <body>
- <iframestyle="display:none"name="ifm"></iframe>
- <formenctype="multipart/form-data"method="POST"action="upload.php"target="ifm"name="myform">
- <inputtype="hidden"name="APC_UPLOAD_PROGRESS"id="remark">
- <inputtype="file"name="upfile"/>
- <inputtype="submit"value="上传"name="sub"/>
- </form>
- <divid="progress"class="before"><spanid="pecent"></span></div>
- <scripttype="text/javascript">
- (function(){
- functionaddEvent(node,type,listener){
- if(node.addEventListener){
- //W3Cmethod
- node.addEventListener(type,listener,false);
- returntrue;
- }elseif(node.attachEvent){
- //MSIEmethod
- node['e'+type+listener]=listener;
- node[type+listener]=function(){node['e'+type+listener](window.event);}
- node.attachEvent('on'+type,node[type+listener]);
- returntrue;
- }
- //Didn'thaveeithersoreturnfalse
- returnfalse;
- };
- varsubmit=document.forms["myform"];
- addEvent(submit,'submit',startUpload);
- varbegin;
- varrequest;
- varrdm;
- varpec=document.getElementById("pecent");
- functionstartUpload()
- {
- rdm=Math.floor(Math.random()*100000000);
- document.getElementById('remark').setAttribute('value',rdm);
- document.getElementById("progress").style['display']='block';
- //creatXmlHttpRequest();
- begin=setTimeout(doRequest,1000);
- };
- functioncreatXmlHttpRequest()
- {
- if(window.ActiveXObject)
- {request=newActiveXObject("Microsoft.XMLHTTP")}
- else{request=newXMLHttpRequest();}
- };
- varcount=0;
- functiondoRequest()
- {
- if(window.ActiveXObject)
- {request=newActiveXObject("Microsoft.XMLHTTP");}
- else{request=newXMLHttpRequest();}
- if(request!=null){
- request.onreadystatechange=handle;
- request.open("GET","upload.php?key="+rdm+"&sim="+(++count),true);
- request.send();
- }
- };
- functionhandle()
- {
- if(request.readyState==4&&request.status==200)
- {
- //接受服务器数据
- varprgs=eval("("+request.responseText+")");
- //varprgs=request.responseText;
- varcur=parseInt(prgs.current);
- vartotal=parseInt(prgs.total);
- varpecentIs=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
- /*
- *Createdon2010-4-16
- *
- *Tochangethetemplateforthisgeneratedfilegoto
- *Window-Preferences-PHPeclipse-PHP-CodeTemplates
- */
- 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');
- //RetrievethestatususingthegetStatus()functionbelow
- //echojson_encode(getStatusAPC());
- echojson_encode(getStatusAPC());
- }
- functiongetStatusAPC()
- {
- $response=false;
- if($status=apc_fetch('upload_'.$_GET['key'])){
- $response=apc_fetch('upload_'.$_GET['key']);
- }
- return$response;
- }
- ?>
问题总结:
1,使用setTimeout嵌套和setInterval有区别,用前者效果较好,用后者的话由于请求和返回的时间比较随机,时间间隔把握不好的话,程序会比较混乱,结果往往不正确。
2.发送Ajax请求时每次都要重新实例化xmlhttprequest对象而不能用上次实例化的,否则程序在ie下无法执行,在火狐下可以运行