zoukankan      html  css  js  c++  java
  • php利用curl实现多进程下载文件类

    批量下载文件一般使用循环的方式,逐一执行下载。但在带宽与服务器性能允许的情况下,使用多进程进行下载可以大大提高下载的效率。本文介绍PHP利用curl的多进程请求方法,实现多进程同时下载文件。

    原理:

    使用curl的批处理方法,开启多进程,实现批量下载文件。 

    主要方法:

    curl_multi_init 
    返回一个新cURL批处理句柄

    curl_multi_add_handle 
    向curl批处理会话中添加单独的curl句柄

    curl_multi_exec 
    运行当前 cURL 句柄的子连接

    curl_multi_getcontent 
    如果设置了CURLOPT_RETURNTRANSFER,则返回获取的输出的文本流

    curl_multi_remove_handle 
    移除curl批处理句柄资源中的某个句柄资源

    curl_multi_close 
    关闭一组cURL句柄

    /**
     * 多进程批量下载文件(使用php curl_multi_exec实现)
     *
     * Func
     * public  download 下载处理
     * public  process  多进程下载
     * private to_log   将执行结果写入日志文件
     */
    class DownLoad {
    
        // 下载文件设置
        private $download_config = array();
    
        // 最大开启进程数量
        private $max_process_num = 10;
    
        // 超时秒数
        private $timeout = 10;
    
        // 日志文件
        private $logfile = null;
    
        /**
         * 初始化
         * @param  Array  $download_config   下载的文件设置
         * @param  Int    $max_process_num   最大开启的进程数量
         * @param  Int    $timeout           超时秒数
         * @param  String $logfile           日志文件路径
         */
        public function __construct($download_config, $max_process_num=10, $timeout=10, $logfile=''){
            $this->download_config = $download_config;
            $this->max_process_num = $max_process_num;
            $this->timeout = $timeout;
    
            // 日志文件
            if($logfile){
                $this->logfile = $logfile;
            }else{
                $this->logfile = dirname(__FILE__).'/batch_download_'.date('Ymd').'.log';
            }
        }
    
        /**
         * 执行下载
         * @result Int
         */
        public function download(){
    
            // 已处理的数量
            $handle_num = 0;
    
            // 未处理完成
            while(count($this->download_config)>0){
    
                // 需要处理的大于最大进程数
                if(count($this->download_config)>$this->max_process_num){
                    $process_num = $this->max_process_num;
                // 需要处理的小于最大进程数
                }else{
                    $process_num = count($this->download_config);
                }
    
                // 抽取指定数量进行下载
                $tmp_download_config = array_splice($this->download_config, 0, $process_num);
    
                // 执行下载
                $result = $this->process($tmp_download_config);
    
                // 写入日志
                $this->to_log($tmp_download_config, $result);
    
                // 记录已处理的数量
                $handle_num += count($result);
    
            }
    
            return $handle_num;
    
        }
    
        /**
         * 多进程下载文件
         * @param  Array $download_config 本次下载的设置
         * @return Array
         */
        public function process($download_config){
    
            // 文件资源
            $fp = array();
    
            // curl会话
            $ch = array();
    
            // 执行结果
            $result = array();
    
            // 创建curl handle
            $mh = curl_multi_init();
    
            // 循环设定数量
            foreach($download_config as $k=>$config){
                $ch[$k] = curl_init();
                $fp[$k] = fopen($config[1], 'a');
    
                curl_setopt($ch[$k], CURLOPT_URL, $config[0]);
                curl_setopt($ch[$k], CURLOPT_FILE, $fp[$k]);
                curl_setopt($ch[$k], CURLOPT_HEADER, 0);
                curl_setopt($ch[$k], CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch[$k], CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)');
    
                // 加入处理
                curl_multi_add_handle($mh, $ch[$k]);
            }
    
            $active = null;
    
            do{
                $mrc = curl_multi_exec($mh, $active);
            } while($active);
    
            // 获取数据
            foreach($fp as $k=>$v){
                fwrite($v, curl_multi_getcontent($ch[$k]));
            }
    
            // 关闭curl handle与文件资源
            foreach($download_config as $k=>$config){
                curl_multi_remove_handle($mh, $ch[$k]);
                fclose($fp[$k]);
    
                // 检查是否下载成功
                if(file_exists($config[1])){
                    $result[$k] = true;
                }else{
                    $result[$k] = false;
                }
            }
    
            curl_multi_close($mh);
    
            return $result;
    
        }
    
        /**
         * 写入日志
         * @param Array $data 下载文件数据
         * @param Array $flag 下载文件状态数据
         */
        private function to_log($data, $flag){
    
            // 临时日志数据
            $tmp_log = '';
    
            foreach($data as $k=>$v){
                $tmp_log .= '['.date('Y-m-d H:i:s').'] url:'.$v[0].' file:'.$v[1].' status:'.$flag[$k].PHP_EOL;
            }
    
            // 创建日志目录
            if(!is_dir(dirname($this->logfile))){
                mkdir(dirname($this->logfile), 0777, true);
            }
    
            // 写入日志文件
            file_put_contents($this->logfile, $tmp_log, FILE_APPEND);
        }
    
    }

    demo.php

    require 'DownLoad.class.php';
    
    $base_path = dirname(__FILE__).'/photo';
    
    $download_config = array(
        array('http://www.example.com/p1.jpg', $base_path.'/p1.jpg'),
        array('http://www.example.com/p2.jpg', $base_path.'/p2.jpg'),
        array('http://www.example.com/p3.jpg', $base_path.'/p3.jpg'),
        array('http://www.example.com/p4.jpg', $base_path.'/p4.jpg'),
        array('http://www.example.com/p5.jpg', $base_path.'/p5.jpg'),
    );
    
    $obj = new BatchDownLoad($download_config, 2, 10);
    $handle_num = $obj->download();
    
    echo 'download num:'.$handle_num.PHP_EOL;
  • 相关阅读:
    sql server 2008 不允许保存更改,您所做的更改要求删除并重新创建以下表 的解决办法
    给 textbox TextMode="password" 赋值后显示出来
    mysql limit分页优化方法分享
    jquery iframe取得元素与自适应高度
    js动态改变iframe的高度
    完全解读 margin 标签
    Page.ClientScript、ClientScript、ScriptManager、ClientScriptManager等的详细解说
    Asp.net C# 使用Newtonsoft.Json 实现DataTable转Json格式数据
    Newtonsoft.Json(Json.net)的基本用法
    利用navicat创建存储过程、触发器和使用游标的简单实例
  • 原文地址:https://www.cnblogs.com/lh460795/p/7422900.html
Copyright © 2011-2022 走看看