Press "Enter" to skip to content

上传进度支持(Upload progress in sessions)

文件上传进度反馈, 这个需求在当前是越来越普遍, 比如大附件邮件. 在PHP5.4以前, 我们可以通过APC提供的功能来实现. 或者使用PECL扩展uploadprogress来实现.
虽然说, 它们能很好的解决现在的问题, 但是也有很明显的不足:

  • 1. 他们都需要额外安装(我们并没有打算把APC加入PHP5.4)
  • 2. 它们都使用本地机制来存储这些信息, APC使用共享内存, 而uploadprogress使用文件系统(不考虑NFS), 这在多台前端机的时候会造成麻烦.

从PHP的角度来说, 最好的储存这些信息的地方应该是SESSION, 首先它是PHP原生支持的机制. 其次, 它可以被配置到存放到任何地方(支持多机共享).
正因为此, Arnaud Le Blanc提出了针对Session报告上传进度的RFC, 并且现在实现也已经包含在了PHP5.4的主干中.
这个新特性, 提供了一些新的INI配置, 他们和APC的相关配置很类似:

  • session.upload_progress.enabled[=1] : 是否启用上传进度报告(默认开启)
  • session.upload_progress.cleanup[=1] : 是否在上传完成后及时删除进度数据(默认开启, 推荐开启).
  • session.upload_progress.prefix[=upload_progress_] : 进度数据将存储在_SESSION[session.upload_progress.prefix . _POST[session.upload_progress.name]]
  • session.upload_progress.name[=PHP_SESSION_UPLOAD_PROGRESS] : 如果_POST[session.upload_progress.name]没有被设置, 则不会报告进度.
  • session.upload_progress.freq[=1%] : 更新进度的频率(已经处理的字节数), 也支持百分比表示'%'.
  • session.upload_progress.min_freq[=1.0] : 更新进度的时间间隔(秒级)

对于如下的上传表单:

<form action="upload.php" method="POST" enctype="multipart/form-data">
 <input type="hidden"
     name="<?php echo ini_get("session.upload_progress.name"); ?>" value="laruence" />
 <input type="file" name="file1" />
 <input type="file" name="file2" />
 <input type="submit" />
</form>

如果我们上传一个足够大的文件(网速要是足够慢就更好:P), 我们就可以从_SESSION中, 得到类似下面的进度信息:

$_SESSION["upload_progress_laruence"] = array(
 "start_time" => 1234567890,   // 请求时间
 "content_length" => 57343257, // 上传文件总大小
 "bytes_processed" => 453489,  // 已经处理的大小
 "done" => false,              // 当所有上传处理完成后为TRUE
 "files" => array(
  0 => array(
   "field_name" => "file1",       // 表单中上传框的名字
   // The following 3 elements equals those in $_FILES
   "name" => "foo.avi",
   "tmp_name" => "/tmp/phpxxxxxx",
   "error" => 0,
   "done" => true,                // 当这个文件处理完成后会变成TRUE
   "start_time" => 1234567890,    // 这个文件开始处理时间
   "bytes_processed" => 57343250, // 这个文件已经处理的大小
  ),
  // An other file, not finished uploading, in the same request
  1 => array(
   "field_name" => "file2",
   "name" => "bar.avi",
   "tmp_name" => NULL,
   "error" => 0,
   "done" => false,
   "start_time" => 1234567899,
   "bytes_processed" => 54554,
  ),
 )
);

这个是不是很方便呢?
但是还是要提醒一下, PHP 5.4还处于开发阶段, 在最终release之前, 任何新特性都可能被调整或者更改. 如果大家有任何建议, 也欢迎反馈, 帮助我们使得PHP变得更好.
谢谢
Johannes的blog也介绍过: http://schlueters.de/blog/archives/151-Upload-Progress-in-PHP-trunk.html
更多更新信息, 请关注: Changelog

29 Comments

  1. alashan007
    alashan007 June 18, 2021

    试了下,没打印出数组,哈哈

  2. Amanda
    Amanda March 27, 2020

    我的个人资料很棒,我已经回答了很多问题,也有很多喜欢的人。

  3. Bleakwind
    Bleakwind May 8, 2016

    当自定义session存储的时候,比如用redis存储session,这时候无论如何也无法取到进度,php手册下面的note也有人反映此问题.

    • Bleakwind
      Bleakwind February 12, 2020

      我记得这个问题的解释在微博里看到过, 但是鸟哥的微博删掉了, 不知道是否有人能告知鸟哥微博的解释? 或者鸟哥能否发一下您当时的解释?

    • Bleakwind
      Bleakwind March 22, 2021

      这个问题是我提的, 鸟哥在微博回复过此问题的解决办法, 有一天我想找这个解决办法发现鸟哥把微博全部删光了, 于是好久也找不出原因. 直到前几天整理微信聊天记录, 发觉我当年把鸟哥的解决方法记录在微信里了, 现在把此问题解决方法贴出来以供有同样问题的人查询:

      PHP7的session upload progress(上传进度)在其他session handler(非文件)的时候不能正常工作,
      原因是如果PHP是以fastcgi的方式运行, 需要关闭nginx的request buffering功能:
      proxy_request_buffering off;
      fastcgi_request_buffering off;

  4. idomai
    idomai October 24, 2015

    那在上传文件的时候 写session是每隔多久写一次呢 要在前端显示的话 那就直接用ajax每隔一定时间去轮训后台脚本 后台脚本再去读取session吗

  5. suibian
    suibian April 2, 2015

    我没有打印出session数组

  6. lj
    lj January 15, 2015

    我没有打印出那个session数组

  7. Gift Market Singapore
    Gift Market Singapore August 23, 2014

    What i do not realize is actually how you are not really
    much more well-appreciated than you may be now.
    You’re very intelligent. You understand thus considerably
    with regards to this topic, made me personally imagine it from a lot of varied angles.
    Its like men and women are not interested except it is something to do with Girl gaga!
    Your individual stuffs nice. At all times take care of it up!

  8. domain
    domain August 23, 2014

    Pretty nice post. I simply stumbled upon your weblog and wished to mention that
    I’ve truly loved surfing around your blog posts. In any case
    I’ll be subscribing to your rss feed and I’m hoping you write again very soon!

  9. topin
    topin August 13, 2014

    session.upload_progress
    在apache下使用没问题,但是在nginx+php的环境,只有文件上传完成之后才会写入$_SESSION, 而此时如果设置了
    session.upload_progress.cleanup[=1]
    session里的值又会被清除,所以一直无法显示出来。

  10. susisoy
    susisoy June 17, 2013

    HTML5 对上传文件进行了重新设计,现在已经可以完全基本客户端自身完成上传进度的展示了。
    遗憾的是现代浏览器还没有太好的普及,但这仅是一个时间问题,这样一来,PHP 的靠 SESSION 实现的上传进度探测就相对低效很多,且实现较好的体验也相对困难些。

  11. anhely
    anhely April 2, 2013

    bytes_processed
    文件已处理的大小怎么写?

  12. anhely
    anhely April 2, 2013

    bytes_processed=?
    这个处理进度应该等于什么?

  13. MagentoEye
    MagentoEye April 24, 2012

    这个功能太实用了!

  14. silence
    silence February 21, 2012

    php-5.4.0RC7-Win32-VC9-x86.zip下测试是支持的,是我的方法不对,现在解决了

  15. spring
    spring February 16, 2012

    你好,我在php-5.4.0RC7-Win32-VC9-x86.zip下测试此特性貌似不管用哦????

  16. leo
    leo December 21, 2011

    这个好!!

  17. 荒野无灯
    荒野无灯 November 6, 2011

    有原生支持就比较好了。

  18. solu
    solu November 3, 2011

    这功能太实用了!

  19. jackywdx
    jackywdx October 10, 2011

    cool

  20. pAUL gAO
    pAUL gAO October 10, 2011

    也可以用 NGINX 的扩展支持,好处是上传时不会消耗 PHP 进程。

  21. wclssdn
    wclssdn October 10, 2011

    这个就太帅了~~~ 哈哈哈

Comments are closed.