<?php

namespace network;
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2022/8/18
 * Time: 13:00
 */
class CurlHelper
{
    private $curl;
    private $showResponseHeader = false;
    private $responseHeader;
    private $showRequestHeader = false;
    private $requestHeader;
    private $response;
    private $responseBody;
    private $httpCode;
    private $error;

    public function __construct($url, $params = [])
    {
        $this->curl = curl_init();
        curl_setopt($this->curl, CURLOPT_URL, $url);
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);//要求结果为字符串且输出到屏幕上
        curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, true);//跟踪爬取重定向页面
        curl_setopt($this->curl, CURLOPT_MAXREDIRS, 10);//表示最多允许重定向多少次
        curl_setopt($this->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        $this->setUserAgent();
        $this->setTimeout();
        $this->setEncoding();
        //跳过https证书验证
        if (substr($url, 0, 5) == 'https') {
            $this->sslVerify();
        }
        $this->setParams($params);
    }

    /**
     * @param string $userAgent
     */
    public function setUserAgent($userAgent = '')
    {
        if (!$userAgent) {
            $userAgent = empty($_SERVER['HTTP_USER_AGENT']) ? 'Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)' : $_SERVER['HTTP_USER_AGENT'];//模拟用户使用的浏览器
        }
        curl_setopt($this->curl, CURLOPT_USERAGENT, $userAgent);
    }

    /**
     * 设置超时
     * @param int $connect_timeout
     * @param int $timeout
     */
    public function setTimeout($connect_timeout = 10, $timeout = 300)
    {
        curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT, $connect_timeout);//连接超时时间
        curl_setopt($this->curl, CURLOPT_TIMEOUT, $timeout);//数据传输的最大允许时间, 默认为0，意思是永远不会断开链接
    }

    /**
     * 设置请求参数
     * @param $params array
     */
    public function setParams($params)
    {
        if ($params) {
            // post请求
            curl_setopt($this->curl, CURLOPT_POST, true);
            // $post_data为array类型时multipart/form­data请求，string类型时application/x-www-form-urlencoded
            curl_setopt($this->curl, CURLOPT_POSTFIELDS, $params);
        } else {
            // get请求
            curl_setopt($this->curl, CURLOPT_HTTPGET, true);
        }
    }

    /**
     * 设置代理
     * @param $proxy_host string
     * @param $proxy_port int
     */
    public function setProxy($proxy_host, $proxy_port)
    {
        curl_setopt($this->curl, CURLOPT_PROXY, $proxy_host);
        curl_setopt($this->curl, CURLOPT_PROXYPORT, $proxy_port);
    }

    /**
     * 默认跳过https证书验证
     * @param bool $ignore
     */
    public function sslVerify($ignore = false)
    {
        if ($ignore) {
            curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, TRUE);//严格校验
            curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, 2);//严格校验
        } else {
            curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false);//跳过证书检查
            curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);//从证书中检查SSL加密算法是否存在
        }
    }

    /**
     * 设置证书，默认不需要
     * @param $sslCertPath string
     * @param $sslKeyPath string
     */
    public function useCert($sslCertPath, $sslKeyPath)
    {
        //设置证书,证书路径,注意应该填写绝对路径
        //使用证书：cert 与 key 分别属于两个.pem文件
        //证书文件请放入服务器的非web目录下,防止被他人下载
        curl_setopt($this->curl, CURLOPT_SSLCERTTYPE, 'PEM');
        curl_setopt($this->curl, CURLOPT_SSLCERT, $sslCertPath);
        curl_setopt($this->curl, CURLOPT_SSLKEYTYPE, 'PEM');
        curl_setopt($this->curl, CURLOPT_SSLKEY, $sslKeyPath);
    }

    /**
     * @param $referer string
     */
    public function setReferer($referer)
    {
        if ($referer) {
            curl_setopt($this->curl, CURLOPT_REFERER, $referer);
        }
    }

    /**
     * 设置转码
     * @param string $encode 默认是可解压缩gzip、deflate等压缩文件
     */
    public function setEncoding($encode = '')
    {
        curl_setopt($this->curl, CURLOPT_ENCODING, $encode);
    }

    /**
     * @param $header array
     */
    public function setHeader($header)
    {
        if (!$header) {
            return;
        }
        // 将索引数组转为键值数组
        // 例如：['User-Agent' => 'Mozilla/5.0 (Windows NT 6.1; WOW64)'] 转为 ['User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64)']
        if (!isset($header[0])) {
            foreach ($header as $hk => $hv) {
                unset ($header [$hk]);
                $header [] = $hk . ':' . $hv;
            }
        }
        curl_setopt($this->curl, CURLOPT_HTTPHEADER, $header);
    }

    /**
     * @param $cookie string
     */
    public function setCookie($cookie)
    {
        if ($cookie) {
            curl_setopt($this->curl, CURLOPT_COOKIE, $cookie);
        }
    }

    /**
     * 获取响应头
     */
    public function showResponseHeader()
    {
        curl_setopt($this->curl, CURLOPT_HEADER, true);//显示响应内容+响应头
        $this->showResponseHeader = true;
    }

    /**
     * 获取请求头
     */
    public function showRequestHeader()
    {
        curl_setopt($this->curl, CURLINFO_HEADER_OUT, true);
        $this->showRequestHeader = true;
    }

    //执行请求
    public function exec()
    {
        // 发送请求
        $this->response = curl_exec($this->curl);
        $this->httpCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);

        if ($error = curl_error($this->curl)) {
            $this->error = $error;
        } else {
            if ($this->showRequestHeader) {// 请求头
                $this->requestHeader = curl_getinfo($this->curl, CURLINFO_HEADER_OUT);
            }
            //头信息大小，curl 在这里有 BUG，需要升级到7.4 或 7.5
            $headerSize = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
            $this->responseBody = substr($this->response, $headerSize);
            $this->responseHeader = substr($this->response, 0, $headerSize);
        }
        curl_close($this->curl);//结束
    }

    //响应状态码
    public function getHttpCode()
    {
        return $this->httpCode;
    }

    //响应内容
    public function getResponse()
    {
        if ($this->showResponseHeader) {
            return $this->responseBody;
        }
        return $this->response;
    }

    //响应的错误消息
    public function getError()
    {
        return $this->error;
    }

    //响应体
    public function getResponseBody()
    {
        return $this->responseBody;
    }

    //请求头
    public function getRequestHeader()
    {
        return $this->showRequestHeader ? $this->requestHeader : '';
    }

    //响应头
    public function getResponseHeader()
    {
        return $this->showResponseHeader ? $this->responseHeader : '';
    }
}