ssl_cert_file; } /** * @param string $ssl_cert_file */ public function setSslCertFile(string $ssl_cert_file) { $this->ssl_cert_file = $ssl_cert_file; } /** * @return string */ public function getSslKeyFile(): string { return $this->ssl_key_file; } /** * @param string $ssl_key_file */ public function setSslKeyFile(string $ssl_key_file) { $this->ssl_key_file = $ssl_key_file; } /** */ public static function NewRequest() { static $client = null; if (!($client instanceof HttpClient)) { $client = new HttpClient(); } return $client; } /** * @param string $name * @return $this */ public function setErrorField(string $name) { $this->errorCodeField = $name; return $this; } /** * @param $bool * @return $this */ public function setUseSwoole($bool) { $this->use_swoole = $bool; return $this; } /** * @param string $name * @return $this */ public function setErrorMsgField(string $name) { $this->errorMsgField = $name; return $this; } /** * @param string $host */ public function setHost(string $host) { $this->host = $host; } /** * @param array $header */ public function setHeader(array $header) { $this->header = $header; } /** * @param $key * @param $value */ public function addHeader($key, $value) { $this->header[$key] = $value; } /** * @param null $callback */ public function setCallback($callback) { $this->callback = $callback; } /** * @param string $method */ public function setMethod(string $method) { $this->method = $method; } /** * @param string $url */ public function setUrl(string $url) { $this->url = $url; } public function setAgent(string $agent) { $this->agent = $agent; } /** * @param bool $isSSL */ public function setIsSSL(bool $isSSL) { $this->isSSL = $isSSL; if ($this->isSSL) { $this->port = 443; } } public function setPort($port) { $this->port = $port; } /** * @return bool */ public function getIsSSL() { return $this->isSSL; } /** * @param bool $isFIle * 设置返回类型 */ public function asFileStream($isFIle = true) { $this->isFileStream = $isFIle; } /** * @param $url * @param array $data * @return array|mixed|Result * @throws \Exception */ private function request($url, $data = []) { $data = $this->paramEncode($data); if ($this->use_swoole === false) { return $this->useCurl($url, $data); } if (function_exists('getIsCli') && getIsCli()) { return $this->coroutine($this->parseUrlHost($url), $url, $data); } return $this->useCurl($url, $data); } /** * @param $url * @param $data * @return array|Result|mixed */ private function useCurl($url, $data) { if ($this->isHttp($url) || $this->isHttps($url)) { return $this->curl($url, $data); } if ($this->isSSL) { return $this->curl('https://' . $this->host . '/' . $url, $data); } else { return $this->curl('http://' . $this->host . '/' . $url, $data); } } /** * @param $url * @return string */ private function parseUrlHost(&$url) { if (!empty($this->host)) { return $this->host; } if ($this->isHttp($url)) { $url = str_replace('http://', '', $url); } else if ($this->isHttps($url)) { $url = str_replace('https://', '', $url); } $explode = explode('/', $url); $first = array_shift($explode); if (strpos($first, ':') !== false) { [$first, $this->port] = explode(':', $first); if ($this->port !== 443) { $this->isSSL = false; } $url = '/' . implode('/', $explode); } if (preg_match('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $first)) { return $first; } return System::gethostbyname($first); } /** * @param $url * @return bool */ private function isHttp($url) { return strpos($url, 'http://') === 0; } /** * @param $url * @return bool */ private function isHttps($url) { return strpos($url, 'https://') === 0; } /** * @param $ip * @param $url * @param array $data * @return array|mixed|Result * @throws \Exception * 使用swoole协程方式请求 */ private function coroutine($ip, $url, $data = []) { $client = $this->generate_client($ip, $url, $data); if ($client->statusCode < 0) { throw new \Exception($client->errMsg); } $body = $client->body; $client->close(); $header = $client->getHeaders(); $body = $this->resolve($header, $body); if ($client->getStatusCode() != 200) { return new Result(['code' => $client->getStatusCode(), 'message' => $body, 'header' => $header]); } return $this->structure($body, $data, $header); } /** * @return mixed */ private function getHostIp() { $host = \Co::getAddrInfo($this->host); return array_shift($host); } /** * @return int */ private function getHostPort() { if (!empty($this->port)) { return $this->port; } $port = 80; if ($this->isSSL) $port = 443; return $port; } /** * @param $host * @param $port * @param $url * @param $data * @return \Swoole\Coroutine\Http\Client */ private function generate_client($host, $url, $data) { $client = new SClient($host, $this->getHostPort(), $this->isSSL); if (!empty($this->agent)) { $this->header['User-Agent'] = $this->agent; } if (!empty($this->header)) { $client->setHeaders($this->parseHeaderMat()); } if (strtolower($this->method) == self::GET) { $client->get($url . '?' . $data); } else if (strtolower($this->method) == self::PUT) { $client->setMethod('PUT'); if (!is_string($data)) { $data = json_encode($data, JSON_UNESCAPED_UNICODE); } $client->setData($data); $client->execute($url); } else if (strtolower($this->method) == self::DELETE) { $client->setMethod('DELETE'); if (!is_string($data)) { $data = json_encode($data, JSON_UNESCAPED_UNICODE); } $client->setData($data); $client->execute($url); } else { $client->post($url, $data); } return $client; } /** * @param $url * @param array $data * @return array|mixed|Result */ private function curl($url, $data = []) { try { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->createRequestUrl($url, $data)); curl_setopt($ch, CURLOPT_TIMEOUT, 5);// 超时设置 curl_setopt($ch, CURLOPT_HEADER, true); if ($headers = $this->parseHeaderMat()) { curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } if (!empty($this->agent)) { curl_setopt($ch, CURLOPT_USERAGENT, $this->agent); } curl_setopt($ch, CURLOPT_SSLCERT, $this->getSslCertFile()); curl_setopt($ch, CURLOPT_SSLKEY, $this->getSslKeyFile()); curl_setopt($ch, CURLOPT_NOBODY, FALSE); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1); // 超时设置 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);//返回内容 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);// 跟踪重定向 curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate'); if ($this->method == self::POST) { curl_setopt($ch, CURLOPT_POST, 1); } if ($this->method != self::GET) { curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($this->method)); $output = curl_exec($ch); curl_close($ch); if ($output === FALSE) { return new Result(['code' => 500, 'message' => curl_error($ch)]); } list($header, $body) = explode("\r\n\r\n", $output, 2); $header = explode(PHP_EOL, $header); $status = (int)explode(' ', trim($header[0]))[1]; $header = $this->headerFormat($header); if ($status != 200) { return new Result(['code' => 500, 'message' => $body, 'header' => $header]); } return $this->structure($this->resolve($header, $body), $data, $header); } catch (\Exception $exception) { return new Result(['code' => 500, 'message' => $exception->getMessage(), 'header' => []]); } } /** * @param $url * @param $data * @return string */ private function createRequestUrl($url, $data) { if ($this->isGet()) { return $url . '?' . $data; } return $url; } /** * @param $data * @param $body * @return mixed */ private function resolve($data, $body) { $type = $data['Content-Type'] ?? $data['content-type']; if (strpos($type, 'json') !== false) { return json_decode($body, true); } else if (strpos($type, 'xml') !== false) { $data = simplexml_load_string($body, 'SimpleXMLElement', LIBXML_NOCDATA); return json_decode(json_encode($data), TRUE); } else if (strpos($type, 'plain') !== false) { return json_decode($data, TRUE); } else { return $body; } } /** * @param $headers * @return array */ private function headerFormat($headers) { $_tmp = []; foreach ($headers as $key => $val) { $trim = explode(': ', trim($val)); $_tmp[$trim[0]] = $trim[1] ?? ''; } return $_tmp; } /** * @param $body * @param $_data * @param $header * @param $statusCode * @return array|mixed|Result * 构建返回体 */ private function structure($body, $_data, $header = [], $statusCode = 200) { $this->setIsSSL(false); $this->setHeaders([]); if ($this->callback !== NULL) { $result = call_user_func($this->callback, $body, $_data, $header); $this->setCallback(null); return $result; } if (!is_array($body)) { return $body; } $result['code'] = $body[$this->errorCodeField] ?? 0; $result['message'] = $body[$this->errorMsgField] ?? 'system success.'; $result['data'] = $body; $result['header'] = $header; $result['httpStatus'] = $statusCode; return new Result($result); } /** * @return bool * check isPost Request */ public function isPost() { return strtolower($this->method) === self::POST; } /** * @return bool * * check isGet Request */ public function isGet() { return strtolower($this->method) === self::GET; } /** * @param $arr * * @return array|string * 将请求参数进行编码 */ private function paramEncode($arr) { if (!is_array($arr)) { return $arr; } $_tmp = []; foreach ($arr as $Key => $val) { $_tmp[$Key] = $val; } if ($this->isGet()) { return http_build_query($_tmp); } return $_tmp; } /** * @param $url * @param array $data * @return array|mixed|Result * @throws */ public function post($url, $data = []) { $this->setMethod(self::POST); return $this->request($url, $data); } /** * @param $url * @param array $data * @return array|mixed|Result * @throws */ public function put($url, $data = []) { $this->setMethod(self::PUT); return $this->request($url, $data); } /** * @param $url * @param array $data * @return array|mixed|Result * @throws */ public function get($url, $data = []) { $this->setMethod(self::GET); return $this->request($url, $data); } /** * @param $url * @param array $data * @return array|mixed|Result * @throws \Exception */ public function option($url, $data = []) { $this->setMethod(self::OPTIONS); return $this->request($url, $data); } /** * @param $url * @param array $data * @return array|mixed|Result * @throws \Exception */ public function delete($url, $data = []) { $this->setMethod(self::DELETE); return $this->request($url, $data); } /** * @param $url * @param array $data * @return array|mixed|Result * @throws \Exception */ public function send($url, $data = []) { return $this->request($url, $data); } /** * @return array */ private function parseHeaderMat() { if ($this->use_swoole) { return $this->header; } $headers = []; foreach ($this->header as $key => $val) { $header = $key . ':' . $val; if (in_array($header, $headers)) { continue; } $headers[] = $header; } $this->header = []; return $headers; } /** * @param array $headers * @return array */ public function setHeaders(array $headers) { if (empty($headers)) { return []; } foreach ($headers as $key => $val) { $header = $key . ':' . $val; if (in_array($header, $this->header)) { continue; } $this->header[] = $header; } return $this->header; } }