V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
DavidNineRoc
V2EX  ›  PHP

[CLI] 使用 Curl 下载文件实时进度条显示

  •  
  •   DavidNineRoc · 2018-03-24 23:02:45 +08:00 · 3937 次点击
    这是一个创建于 2441 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在捣鼓命令行下的编程,下载文件总是一个难熬的过程,如果有进度条就好很多了!!!


    先上一个进度条的扩展包,还是不错的https://github.com/dariuszp/cli-progress-bar https://github.com/dariuszp/cli-progress-bar/raw/master/examples/img/terminal.gif 还是挺好看的!


    curl做为 PHP 一个很常用的下载方式,这里简单的使用方式;

    // 初始化一个 curl
    $ch = curl_init();
    // 设置请求的 url
    curl_setopt($ch, CURLOPT_URL, $url);
    // 
    curl_setopt($ch, CURLOPT_HEADER, 0);
    // 不直接输出,而是通过 curl_exec 返回
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    
    if (false === ($stream = curl_exec($ch))) {
        throw new \Exception(curl_errno($ch));
    }
    
    curl_close($ch);
    
    return $stream;
    

    上面是一个很简单的例子,如果一个文件很大,那么用户就需要等待很长的时间,这时候我们就应该加上进度条的效果:

    class Request
    {
        protected $bar;
        // 是否下载完成
        protected $downloaded = false;
    
        public function __construct()
        {
            // 初始化一个进度条
            $this->bar = new CliProgressBar(100);
            $this->bar->display();
            $this->bar->setColorToRed();
        }
        
        function download($url)
        {
            $ch = curl_init();
        
            // 从配置文件中获取根路径
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
            // 开启进度条
            curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
            // 进度条的触发函数
            curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progress');
            // ps: 如果目标网页跳转,也跟着跳转
            // curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        
            if (false === ($stream = curl_exec($ch))) {
                throw new \Exception(curl_errno($ch));
            }
        
            curl_close($ch);
        
            return $stream;
        }
        
        /**
         * 进度条下载.
         *
         * @param $ch
         * @param $countDownloadSize    总下载量
         * @param $currentDownloadSize  当前下载量
         * @param $countUploadSize      
         * @param $currentUploadSize
         */
        public function progress($ch, $countDownloadSize, $currentDownloadSize, $countUploadSize, $currentUploadSize)
        {
            
             // 等于 0 的时候,应该是预读资源不等于 0 的时候即开始下载
             // 这里的每一个判断都是坑,多试试就知道了
            if (0 === $countDownloadSize) {
                return false;
            }
            // 有时候会下载两次,第一次很小,应该是重定向下载
            if ($countDownloadSize > $currentDownloadSize) {
                $this->downloaded = false;
                // 继续显示进度条
            }
            // 已经下载完成还会再发三次请求
            elseif ($this->downloaded) {
                return false;
            }
            // 两边相等下载完成并不一定结束,
            elseif ($currentDownloadSize === $countDownloadSize) {
                return false;
            }
            
            // 开始计算
            $bar = $currentDownloadSize / $countDownloadSize * 100;
            $this->bar->progress($bar);
        }
    }
    (new Request)->download('http://www.shiguopeng.cn/database.sql');
    

    千万千万注意下载回调的判断那里的坑!!!

    • 还有一个问题:如果跳转下载的,设置了curl也跟着跳转,返回的文件将会出问题,
    • 我下载的是zip文件,会导致文件头有第一此请求的HTTP响应头的内容,
    • 所以看自己需要curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    第 1 条附言  ·  2018-03-25 09:38:38 +08:00
    是 PHP 里的 curl
    7 条回复    2018-03-25 09:39:25 +08:00
    isCyan
        1
    isCyan  
       2018-03-24 23:10:52 +08:00 via Android
    curl 本身不就有吗我记得
    akira
        2
    akira  
       2018-03-24 23:17:15 +08:00
    --progress-bar
    lfzyx
        3
    lfzyx  
       2018-03-24 23:18:04 +08:00
    --progress-bar
    Humorce
        4
    Humorce  
       2018-03-24 23:37:08 +08:00 via iPhone
    哈哈
    yianing
        5
    yianing  
       2018-03-25 07:27:10 +08:00
    wget 不是用来下载文件的吗?
    DavidNineRoc
        6
    DavidNineRoc  
    OP
       2018-03-25 09:38:24 +08:00
    @isCyan curl 提供触发的函数
    DavidNineRoc
        7
    DavidNineRoc  
    OP
       2018-03-25 09:39:25 +08:00
    @akira
    @lfzyx 忘记说了,是 PHP 里的 curl

    @yianing PHP 里的 >_<
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3429 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 10:42 · PVG 18:42 · LAX 02:42 · JFK 05:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.