joinGetParams($path, $params); } $this->getCurlHandler($path, $method, $params); $this->execute(); } /** * @param string $path * @param string $method * @param $params * * @return void */ private function getCurlHandler(string $path, string $method, $params): void { $host = $this->isSSL ? 'https://' . $this->host : 'http://' . $this->host; if ($this->getPort() != 443 && $this->getPort() != 80) { $host .= ':' . $this->getPort(); } $this->do(curl_init($host . $path), $host . $path, $method); if ($this->isSSL) { $this->curlHandlerSslSet(); } $contents = $this->_data; if (empty($params) && empty($contents)) { return; } if (!empty($contents)) { curl_setopt($this->client, CURLOPT_POSTFIELDS, $contents); } else if ($method === self::UPLOAD) { curl_setopt($this->client, CURLOPT_POSTFIELDS, $params); } else if ($method === self::POST) { if (is_array($params)) { $params = http_build_query($params); } curl_setopt($this->client, CURLOPT_POSTFIELDS, $params); } } /** * @return void * @throws */ private function curlHandlerSslSet(): void { if (!empty($this->ssl_key_file) && file_exists($this->ssl_key_file)) { curl_setopt($this->client, CURLOPT_SSLKEY, $this->ssl_key_file); } if (!empty($this->ssl_cert_file) && file_exists($this->ssl_cert_file)) { curl_setopt($this->client, CURLOPT_SSLCERT, $this->ssl_cert_file); } if (!empty($this->ca) && file_exists($this->ca)) { curl_setopt($this->client, CURLOPT_CAINFO, $this->ca); } } /** * @param mixed $resource * @param string $path * @param string $method * * @return void */ private function do(mixed $resource, string $path, string $method): void { curl_setopt($resource, CURLOPT_URL, $path); curl_setopt($resource, CURLOPT_TIMEOUT, $this->timeout); // 超时设置 curl_setopt($resource, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout); // 超时设置 curl_setopt($resource, CURLOPT_HEADER, TRUE); curl_setopt($resource, CURLOPT_FAILONERROR, TRUE); curl_setopt($resource, CURLOPT_HTTPHEADER, $this->parseHeaderMat()); if (defined('CURLOPT_SSL_FALSESTART')) { curl_setopt($resource, CURLOPT_SSL_FALSESTART, TRUE); } curl_setopt($resource, CURLOPT_FORBID_REUSE, FALSE); curl_setopt($resource, CURLOPT_FRESH_CONNECT, FALSE); if (!empty($this->agent)) { curl_setopt($resource, CURLOPT_USERAGENT, $this->agent); } curl_setopt($resource, CURLOPT_NOBODY, FALSE); curl_setopt($resource, CURLOPT_RETURNTRANSFER, TRUE);//返回内容 curl_setopt($resource, CURLOPT_FOLLOWLOCATION, TRUE);// 跟踪重定向 curl_setopt($resource, CURLOPT_ENCODING, 'gzip,deflate'); if ($method === self::POST || $method == self::UPLOAD) { curl_setopt($resource, CURLOPT_POST, 1); } [$proxy, $port] = [$this->proxyHost, $this->proxyPort]; if (!empty($proxy) && $port > 0) { curl_setopt($resource, CURLOPT_PROXYPORT, $port); curl_setopt($resource, CURLOPT_PROXY, $proxy); } curl_setopt($resource, CURLOPT_CUSTOMREQUEST, strtoupper($method)); $this->client = $resource; if (!empty($this->caPath)) { curl_setopt($this->client, CURLOPT_CAINFO, $this->caPath); } } /** * @var string */ private string $caPath = ''; /** * @param string $path * * @return $this */ public function withCAInfo(string $path): static { $this->caPath = $path; return $this; } /** * @throws */ private function execute(): void { $output = curl_exec($this->client); if ($output !== FALSE) { $this->explode($output); } else { $this->statusCode = curl_errno($this->client); $this->body = curl_error($this->client); } $this->close(); } /** * @return void * @throws */ private function retry(): void { if (($this->num += 1) <= $this->retryNum) { sleep($this->retryTimeout); $this->execute(); } else { $this->statusCode = curl_errno($this->client); $this->body = curl_error($this->client); } } /** * */ public function close(): void { if (PHP_VERSION < '8.0') { curl_close($this->client); } } /** * @param string $output * * @return void * @throws */ private function explode(string $output): void { // 获取 HTTP 状态码 $statusCode = +curl_getinfo($this->client, CURLINFO_HTTP_CODE); // 获取 header 的大小(不包括最后的 \r\n\r\n 分隔符) $headerSize = curl_getinfo($this->client, CURLINFO_HEADER_SIZE); $header = substr($output, 0, $headerSize); if (in_array($statusCode, [502, 404])) { $this->retry(); } else { $this->statusCode = $statusCode; $this->body = substr($output, $headerSize); $this->setResponseHeader(explode("\r\n", $header)); } } /** * @return array */ private function parseHeaderMat(): array { $headers = []; foreach ($this->header as $key => $val) { $headers[$key] = $key . ': ' . $val; } return array_values($headers); } }