资讯专栏INFORMATION COLUMN

PHP 远程文件下载的进度条实现

YJNldm / 1908人阅读

摘要:原文地址实现远程下载文件到服务端并不是什么新鲜玩意,用等都能够轻易实现。原理也许你在搜索下载进度条的时候会看到有些文章使用的输出控制函数之类的控制缓冲区来实现进度条。

原文地址:https://prinzeugen.net/implem...

PHP 实现远程下载文件到服务端并不是什么新鲜玩意,用 cURLfile_get_contentsfopen 等都能够轻易实现。

但是这几种常规的方法都是在一个线程内下载文件,等文件下载完毕以后才能返回 HTTP 响应。所造成的结果就是用户在页面上点击「下载到服务器」按钮后,会看到空白页和加载的小菊花转啊转,转好久之后才出现「下载成功」的页面。

当然,我上面所举例的情况是只使用纯粹的表单 POST 发送请求的情况。现在的话就算再不济也一般会使用 ajax 发送请求,然后在前台放个加载动画,等收到下载成功的回应之后再进行下一步操作。

但是!即使是去掉了恶心的且需要等待的空白页,这样做还是对用户体验有不好的影响。没有具体的下载进度,只有一个一直转呀转的菊花图,估计挺多用户都无法坐和放宽吧(至少对于我来说是这样的)

而我一个 PHP 项目的一键更新系统正好需要重构,遂研究了如何在 PHP 作为后端时显示远程文件下载进度条,并捣鼓出了个像样的解决方案,在这里分享一下。


0x01 原理

也许你在搜索「PHP 下载 进度条」的时候会看到有些文章使用 PHP 的输出控制函数(flush 之类的)控制缓冲区来实现进度条。但是——

那都是狗屁!

没有人可以保证用户的 PHP 关闭了默认开启的 output buffering,也无法保证 浏览器 / Web Server 不对脚本输出进行缓存。如果上述两者其中之一处于开启状态的话,你就会喜闻乐见的发现本应该慢慢增长的进度条会在等待完漫长的 xx 秒后一下子蹦到 100%_(因为控制前端进度条长度的语句被缓存起来,在脚本执行结束后一并发送了,而不是一块一块地传给浏览器)_。

关于上面缓冲区控制的进度条就是辣鸡的更多讨论可以查看文章底部的参考链接。

闲话休提。那么我们该如何实现下载进度条的更新呢?

首先通过后端一点点输出控制进度条语句的方案已经 PASS 了,那么我们很自然的就会想到——

在前端设置一个定时器,Ajax 轮循下载进度并更新页面上的进度条。

0x02 概述

知道了原理之后,我们先来考虑下整体的架构与步骤。

用户点击「下载」按钮,前端展示出进度条,并 ajax 发送 prepare-download 的请求;

后端收到请求,进行远程下载的准备工作 —— 准备好远程文件链接、临时文件存放位置以及文件的大小,并返回给浏览器;

前端拿到文件大小等信息后,发送真正的 start-download 请求(这个请求耗时可能会很长),并启动轮循的计时器

计时器启动后,每隔一段时间发送 get-file-size 请求,获取当前临时文件的大小,计算进度后更新进度条;

直到下载完成。

下面给出前后端代码的实例。

0x03 后端

代码照例放在 Gist 上,加载不出自行解决:

https://gist.github.com/print...

示例代码使用了 ?action=xxx 的 Query String 形式来区分不同的指令,这些请酌情修改。和我业务逻辑有关的一些关键函数都被我替换为浅显易懂的名字(譬如 get_remote_file_url)了,需要你自己去替换实现。

0x04 前端

https://gist.github.com/print...

0x05 效果 & 总结

实例代码用了 fopen 和循环 fwrite 写入一个 chunk 的数据到临时文件,这是借鉴了 KODExplorer 远程下载的函数,在此致谢。另外也有通过 curl_setopt($ch, CURLOPT_FILE, $fp); 给 cURL 设置一个文件句柄的方法,但是我没有测试成功,希望各位也能试一试。

以上。

参考链接

PHP: flush - Manual 的「说明」部分

PHP progress bar - PHP Coding Help - PHP Freaks

What is output buffering? - Stack Overflow

KODExplorer/file.function.php at master

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/22087.html

相关文章

  • PHP配合apc实现上传进度

    摘要:配合实现上传进度条配合实现上传进度条,一直以为是无法做到进度条一个动态的功能,原来还是自己的知识面不够,看到了扩展相关的一些文章,利用扩展达到了动态实现效果。根据找到相关的文章自己并在此基础上做了一些小修改。 PHP配合apc实现上传进度条PHP配合apc实现上传进度条, 一直以为PHP是无法做到进度条一个动态的功能,原来还是自己的知识面不够,看到了apc扩展相关的一些文章,利用apc...

    SolomonXie 评论0 收藏0
  • Drupal 8 结合Nginx实现文件上传进度,提高上传文件性能

    摘要:自带的上传进度功能,需要扩展支持。于是想到利用的模块来实现上传进度。接下来使用模块替代的文件上传功能,目的是提高文件上传的性能。而且可以避免上传大文件时执行超时引起错误。新建一个对象,把设置成刚上传的文件。 Drupal 8 自带的上传进度功能,需要PECL uploadprogress library扩展支持。安装后发现效果还是不太好,不知道什么原因,进度条不能正常显示,而且上传较大...

    SwordFly 评论0 收藏0
  • Drupal 8 结合Nginx实现文件上传进度,提高上传文件性能

    摘要:自带的上传进度功能,需要扩展支持。于是想到利用的模块来实现上传进度。接下来使用模块替代的文件上传功能,目的是提高文件上传的性能。而且可以避免上传大文件时执行超时引起错误。新建一个对象,把设置成刚上传的文件。 Drupal 8 自带的上传进度功能,需要PECL uploadprogress library扩展支持。安装后发现效果还是不太好,不知道什么原因,进度条不能正常显示,而且上传较大...

    keithxiaoy 评论0 收藏0
  • 上传文件时监控读取进度,显示进度

    摘要:我们在使用异步事件处理时还能顺便获得一项优势,那就是能够监控文件的读取进度这对于读取大文件查找错误和预测读取完成时间非常实用。和事件可用于监控读取进度。以下示例演示了如何通过显示进度条来监控读取状态。 我们在使用异步事件处理时还能顺便获得一项优势,那就是能够监控文件的读取进度;这对于读取大文件、查找错误和预测读取完成时间非常实用。 onloadstart 和 onprogress 事件...

    lsxiao 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<