通过curl的并发机制实现php批量下载

<?php

class Download {

    /**
     * 请求超时时间,单位秒
     * @var int
     */
    public $_timeout = 20;

    /**
     * 设置保存路径
     * note:路径最后以 “/” 结束
     * @var string
     */
    private $_savePath = './';

    /**
     * 设置超时时间
     * @param int $second 单位秒
     */
    public function setTimeout($second) {
        $this->_timeout = intval($second);
    }

    /**
     * 设置保存路径
     * @param $path
     */
    public function setSavePath($path) {
        $this->_savePath = $path;
    }

    /**
     * curl批量下载文件
     * @param array $urls 下载链接
     * @param string $callback 回调函数
     * @return array
     */
    public function multiDown(array $urls,$callback)
    {
        if (empty($urls)) {
            return array();
        }

        $urlsMap = array(); //保存curl句柄与url的关联
        $chs = curl_multi_init();
        foreach ($urls as $url) {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);               //请求地址
            curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout); //请求超时时间,如果下载文件比较大,建议将值设置大一点
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);       //设置为1,表示页面不直接输出返回数据
            curl_setopt($ch, CURLOPT_NOSIGNAL, true);          //设置超时,需要设置这一项
            curl_setopt($ch, CURLOPT_HEADER, 0);               //不显示头部信息
            curl_multi_add_handle($chs,$ch);
            $urlsMap[strval($ch)] = $url;
        }

        $active = null;
        $response = array(); //初始化函数返回值
        do {
            if (curl_multi_exec($chs,$active) == CURLE_OK) {
                while ($done = curl_multi_info_read($chs)) {
                    $url = $urlsMap[strval($done['handle'])];
                    $args = $this->_getCurlDetail($done['handle'],$url);
                    if ($callback && method_exists($this,$callback)) {
                        $this->$callback($args);
                    }
                    $response[$url] = $args;
                    curl_multi_remove_handle($chs,$done['handle']);
                    curl_close($done['handle']);
                }
            }
        } while ($active > 0);

        curl_multi_close($chs);
        return $response;
    }

    /**
     * 获取curl信息(错误,信息,内容,请求url)
     * @param $ch curl句柄
     * @param $url
     * @return array
     */
    private function _getCurlDetail($ch,$url)
    {
        $args = array();

        if (empty($ch)) {
            return $args;
        }

        $args['error'] = curl_error($ch);
        $args['info'] = curl_getinfo($ch);
        $args['result'] = curl_multi_getcontent($ch);
        $args['url'] = $url;
        return $args;
    }

    /**
     * 处理curl返回数据
     * @param $args
     */
    private function _dealData($args)
    {
        if (empty($args['error'])) {
            if ($args['info']['http_code'] == '200') {
                $color = 'green';
                file_put_contents($this->_getFilename($args['url']),$args['result']);
            } else {
                $color = 'orange';
            }
            $content = $args['url'].' -- '.$args['info']['http_code'];
        } else {
            $color = 'red';
            $content = $args['url'].' -- '.$args['error'];
        }

        $this->_showHtml($content,$args['url'],$color);
    }

    /**
     * 格式化显示内容
     * @param $content
     * @param $url
     * @param $color
     */
    private function _showHtml($content,$url,$color)
    {
        echo '<li>';
        echo '<a href="'.$url.'" style="color: '.$color.'">'.$content.'</a>';
        echo '</li>';
    }

    /**
     * 根据url生成文件名
     * note:该方法需要根据实际url情况重写,这里的方法并不完善
     * @param $url
     * @param string $ext 文件后缀名,默认为zip
     * @param bool $isRename 是否重新命名
     * @return string
     */
    private function _getFilename($url,$ext = '.zip',$isRename = true)
    {
        if ($filename = strrchr($url,'/')) {
            if (strpos($filename,'.') === false) {
                $filename = rand(1,99999).$ext;
            }
        }
        $filename = $this->_savePath.$filename;
        if (file_exists($filename) && $isRename) {
            $filename .= rand(1,9999);
        }
        return $filename;
    }
}


//使用方法
$download = new Download();

//下载队列
$urls = array(
    'https://img-my.csdn.net/uploads/201212/28/1356680367_3703.jpg',
    'http://newtab.firefoxchina.cn/img/sitenav/logo.png',
);
$download->setTimeout(10);
$download->setSavePath('./');
$result = $download->multiDown($urls,'_dealData');
//var_dump($result);

参考博客:http://www.eer3.com/article/artdetails/40.htm

转载于:https://my.oschina.net/wuzhencan/blog/648294

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PHP并发CURL是指在PHP中同时发送多个HTTP请求,以提高程序的执行效率和响应速度。通常情况下,PHP使用单线程处理请求,即每次只能处理一个请求,而并发CURL可以在同一时间内处理多个请求。 在PHP实现并发CURL可以使用多种方法,其中比较常用的有以下两种: 1. 使用curl_multi_*函数:PHP提供了一组用于处理并发CURL请求的函数,如curl_multi_init、curl_multi_add_handle、curl_multi_exec等。通过这些函数,可以创建一个CURL多句柄,将多个请求添加到句柄中,并同时执行这些请求。使用这种方法需要注意处理返回结果和错误信息。 2. 使用第三方库或框架:除了原生的curl_multi_*函数,还可以使用一些第三方库或框架来简化并发CURL实现。例如,Guzzle是一个流行的PHP HTTP客户端库,它提供了简洁的API来处理并发请求,并且支持更多高级功能,如重试、超时控制等。 无论使用哪种方法,实现并发CURL都需要注意以下几点: - 设置合适的并发请求数量:过多的并发请求可能会导致服务器负载过高,而过少的并发请求可能无法充分利用服务器资源。需要根据具体情况设置合适的并发请求数量。 - 处理返回结果:并发CURL请求的返回结果通常是异步的,需要适当处理返回结果,如解析响应数据、处理错误信息等。 - 错误处理:在并发CURL请求中,可能会出现一些错误,如连接超时、请求失败等。需要适当处理这些错误,以保证程序的稳定性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值