PHP基JMathai封装并行Curl请求类,绑定回调处理每个结果

获取扩展:

composer require jmathai/php-multi-curl:dev-master -v

整体思路:

每个请求绑定一个callback回调,处理完每个请求后,将结果通过绑定的回调参数传回

开箱即用的类:

<?php
require_once './vendor/autoload.php';
class MultiLibrary
{
    private $curls;
    private $headers;
    private $callbacks;
    private $objs;
    private $mc;

    public function __construct()
    {
        $this->mc = JMathai\PhpMultiCurl\MultiCurl::getInstance();
    }

    public function Curl($url, $data = array(), $header = array(), $method = 'POST', $timeout = 5, $others = array(), $error = true)
    {
        $ch    = $this->getCurlCh($url, $data, $header, $method, $timeout, $others);
        $ret   = curl_exec($ch);
        $errno = curl_errno($ch);
        $res   = curl_getinfo($ch);
        if (true === $error) {
            curl_error_log($ch, $ret, $url);
        }
        curl_close($ch);
        $result  = array('ret' => $ret, 'errno' => $errno, 'res' => $res);
        return $result;
    }

    private function getCurlCh(&$url, $data = array(), $header = array(), $method = 'POST', $timeout = 2, $others = array(), $ch = null)
    {
        if (empty($ch)) {
            $ch = curl_init();
        }
        if (!preg_match('/\?/', $url)) {
            $url = $url . '?';
        }
        if ('GET' === strtoupper($method) && is_array($data)) {
            $url = $url . '&' . http_build_query($data);
        }
        $url = $url . '&log_id=' . LogId::getLogId();

        //增加鉴权参数
        $app_key                  = isset($data['app_key']) ? $data['app_key'] : 'uc';
        $client_time              = isset($data['client_time']) ? $data['client_time'] : intval(microtime(true) * 1000);
        $url                      = $url . '&app_key=' . $app_key . '&client_time=' . $client_time;
        $header['X-Access-Token'] = 'uc';

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_ENCODING, '');
        /**
         * 设置post信息
         */
        if ('POST' === strtoupper($method)) {
            if (is_array($data)) {
                curl_setopt($ch, CURLOPT_POST, count($data));
            } else {
                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
                curl_setopt($ch, CURLOPT_POST, 1);
            }
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }
        if ('DELETE' === strtoupper($method)) {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }
        /**
         * 设置超时时间
         */
        curl_setopt($ch, CURLOPT_TIMEOUT_MS, intval($timeout * 1000));
        /**
         * 设置header参数
         */
        if (!empty($header) && is_array($header)) {
            $tmp = array();
            foreach ($header as $key => $value) {
                $tmp[] = trim($key) . ': ' . trim($value);
            }
            curl_setopt($ch, CURLOPT_HTTPHEADER, $tmp);
        }
        /**
         * 设置其它信息
         */
        if (is_array($others) && !empty($others)) {
            foreach ($others as $key => $value) {
                curl_setopt($ch, $key, $value);
            }
        }
        return $ch;
    }

    public function addRequest($cfg, $headers, $obj, $cb)
    {
        $this->curls[] = $this->getCfg($cfg);
        $this->headers[] = $this->getHeaders($headers);
        $this->objs[] = $obj;
        $this->callbacks[] = $cb;
    }

    private function getCfg($cfg)
    {
        $requestConfig = [];

        $url = $cfg['protocol'] . '://' . $cfg['ip'] . ':' . $cfg['port'] . $cfg['url'];
        $querystr = http_build_query($cfg['data']);
        $requestConfig['url'] = $url.'?'.$querystr;

        $requestConfig['timeout'] = $cfg['timeout'];
        $requestConfig['connect_timeout'] = $cfg['connect_timeout'];

        $url = $requestConfig['url'];
        $connect_timeout  = $requestConfig['connect_timeout'];
        $timeout  = $requestConfig['timeout'];
        $requestConfig['log_id'] = $cfg['log_id'];
        $requestConfig['ch'] = curl_init($url);
        $requestConfig['url'] = $url;
        curl_setopt($requestConfig['ch'], CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($requestConfig['ch'], CURLOPT_NOSIGNAL, 1);
        if ($connect_timeout > 0) {
            curl_setopt($requestConfig['ch'], CURLOPT_CONNECTTIMEOUT_MS, $connect_timeout);
        }
        if ($timeout > 0) {
            curl_setopt($requestConfig['ch'], CURLOPT_TIMEOUT_MS, $timeout);
        }

        return $requestConfig;
    }

    private function getHeaders($headers)
    {
        $default = [
            'Content-Type' => 'application/json',
        ];
        $headers = array_merge($default, $headers);
        if (!empty($headers) && is_array($headers)) {
            foreach ($headers as $key => $value) {
                $headers[] = trim($key) . ': ' . trim($value);
            }
        }
        return $headers;
    }

    public function execute()
    {
        $result = array();

        //将每个请求添加到curls中
        foreach ($this->curls as $i => $request) {
            $handle = $request['ch'];
            curl_setopt($handle, CURLOPT_HTTPHEADER, $this->headers[$i]);

            $result[] = $this->mc->addCurl($handle);
        }

        foreach ($this->curls as $i => $request) {
            //判断请求成功与否,返回code
            if ($result[$i]->code == 200) {
                $code = 0;
            } else {
                if ($result[$i]->code != 0) {
                    $code = $result[$i]->code;
                } else {
                    if ($result[$i]->curl_code == 0) {
                        $code = 9999; //curl_code和http_code不符合常理
                    } else {
                        $code = $result[$i]->curl_code;
                    }
                }
            }

            $url = $result[$i]->url;

            $logFilename = $this->getUrlFilename($url);
            if (!empty($logFilename)) {
                $data = array();
                if (!empty($url)) {
                    $data['url'] = $url;
                }
                $data['log_id'] = $this->curls[$i]['log_id'];
                $data['connect_time'] = $result[$i]->connect_time;
                $data['time'] = $result[$i]->time;
                $data['http_code'] = $result[$i]->code;
                $data['curl_code'] = $result[$i]->curl_code;
                $data['resp_data'] = $result[$i]->response;

                $file = '/tmp/curl-' . date('Y-m-d', time()) . '.log';
                file_put_contents($file, json_encode($data) . "\n", FILE_APPEND );
            }

            call_user_func_array(
                array($this->objs[$i], $this->callbacks[$i]),
                array($code, '', $result[$i]->response)
            );
        }
    }

    private function getUrlFilename($url)
    {
        if (empty($url)) {
            return '';
        }
        $arr = parse_url($url);
        if (empty($arr['path'])) {
            return '';
        }
        $pathArr = explode('/', $arr['path']);
        if (empty($pathArr)) {
            return '';
        }

        $pathUnderline = implode('_', $pathArr);
        if (empty($pathUnderline)) {
            return '';
        }

        $logPath = "s";
        $d = date("Y-m-d");
        $logFilename = $logPath . $pathUnderline . '-' . $d . ".log";
        return $logFilename;
    }
}


class LogId
{
    static private $logId = '';

    public static function getLogId($reset = false)
    {
        if (!empty(self::$logId) && false === $reset) {
            return self::$logId;
        }
        if (!empty($_SERVER['HTTP_X_YMT_LOGID']) && intval(trim($_SERVER['HTTP_X_YMT_LOGID'])) !== 0) {
            $logid = trim($_SERVER['HTTP_X_YMT_LOGID']);
        } elseif (isset($_REQUEST['logid']) && intval($_REQUEST['logid']) !== 0) {
            $logid = trim($_REQUEST['logid']);
        } else {
            $ip        = intval(self::getHostIp());
            $timestamp = explode(' ', microtime());
            $pack_0    = sprintf('%04d', $timestamp[1] % 3600);
            $pack_1    = sprintf('%04d', intval(($timestamp[0] * 1000000) % 1000));
            $pack_2    = sprintf('%04d', mt_rand(0, 987654321) % 1000);
            $pack_3    = sprintf('%04d', crc32($ip * (mt_rand(0, 987654321) % 1000)) % 10000);
            $logid     = ($pack_0 . $pack_1 . $pack_2 . $pack_3 . $pack_1 . $pack_3);
            //$logid = ((($arr['sec'] * 100000 + $arr['usec'] % 1000) & 0x7FFFFFFF) | 0x80000000);
        }
        return $logid;
    }

    protected static function getHostIp()
    {
        return isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '';
    }
}

Controller:

<?php
require_once 'MultiLibrary.php';

class Index
{
    private $multiLibrary;
    private $requestId;

    private $result = [];

    public function __construct()
    {
        $this->multiLibrary = new MultiLibrary();
        $this->requestId = LogId::getLogId();
    }

    public function index()
    {

        //TODO 3 times multi curl test
        for( $i = 1; $i <= 3; $i++){
            $this->getIndex([]);
        }
        $this->multiLibrary->execute();
        print_r($this->result[0]);
    }

    public function indexCallback($errno, $errmsg, $data)
    {
        if ($errno == 0){
            $this->result[] = $data;
        }
    }

    private function getIndex($data)
    {
        $requestConfig = [
            'data' => $data,
            'protocol' => 'http',
            'ip' => 'www.baidu.com',
            'port' => '80',
            'url' => '',
            'timeout' => 300,
            'connect_timeout' => 300,
            'log_id' => $this->requestId,
        ];
        $headers = [];
        $this->addRequest($requestConfig, $headers, 'indexCallback');
    }

    protected function addRequest(array $params, array $headers, $callback)
    {
        $this->multiLibrary->addRequest($params, $headers, $this, $callback);
    }
}

$obj = new Index();
$obj->index();
发布了253 篇原创文章 · 获赞 47 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/why444216978/article/details/104763396