| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- <?php
- namespace yzh52521\EasyHttp;
- use GuzzleHttp\Handler\CurlHandler;
- use GuzzleHttp\HandlerStack;
- use GuzzleHttp\Middleware;
- use GuzzleHttp\Pool;
- use GuzzleHttp\Client;
- use GuzzleHttp\Promise;
- use GuzzleHttp\Cookie\CookieJar;
- use GuzzleHttp\Exception\ConnectException;
- /**
- * @method \yzh52521\EasyHttp\Response body()
- * @method \yzh52521\EasyHttp\Response array()
- * @method \yzh52521\EasyHttp\Response json()
- * @method \yzh52521\EasyHttp\Response headers()
- * @method \yzh52521\EasyHttp\Response header(string $header)
- * @method \yzh52521\EasyHttp\Response status()
- * @method \yzh52521\EasyHttp\Response successful()
- * @method \yzh52521\EasyHttp\Response ok()
- * @method \yzh52521\EasyHttp\Response redirect()
- * @method \yzh52521\EasyHttp\Response clientError()
- * @method \yzh52521\EasyHttp\Response serverError()
- */
- class Request
- {
- /**
- * \GuzzleHttp\Client单例
- * @var array
- */
- private static $instances = [];
- /**
- * \GuzzleHttp\Client;
- * @var Client
- */
- protected $client;
- /**
- * Body格式
- * @var string
- */
- protected $bodyFormat;
- /**
- * The raw body for the request.
- *
- * @var string
- */
- protected $pendingBody;
- protected $isRemoveBodyFormat = false;
- /**
- * @var array
- */
- protected $options = [];
- /**
- * @var array
- */
- protected $promises = [];
- /**
- * 并发次数
- * @var
- */
- protected $concurrency;
- /**
- *
- * @var HandlerStack
- */
- protected $handlerStack;
- /**
- * Request constructor.
- */
- public function __construct()
- {
- $this->client = $this->getInstance();
- $this->bodyFormat = 'form_params';
- $this->options = [
- 'http_errors' => false,
- ];
- $this->handlerStack = HandlerStack::create(new CurlHandler());
- }
- /**
- * Request destructor.
- */
- public function __destruct()
- {
- }
- /**
- * 获取单例
- * @return mixed
- */
- public function getInstance()
- {
- $name = get_called_class();
- if (!isset(self::$instances[$name])) {
- self::$instances[$name] = new Client();
- }
- return self::$instances[$name];
- }
- public function removeOptions()
- {
- $this->bodyFormat = 'form_params';
- $this->isRemoveBodyFormat = false;
- $this->options = [
- 'http_errors' => false,
- 'verify' => false
- ];
- return $this;
- }
- public function asForm()
- {
- $this->bodyFormat = 'form_params';
- $this->withHeaders(['Content-Type' => 'application/x-www-form-urlencoded']);
- return $this;
- }
- public function asJson()
- {
- $this->bodyFormat = 'json';
- $this->withHeaders(['Content-Type' => 'application/json']);
- return $this;
- }
- public function asMultipart(string $name, string $contents, string $filename = null, array $headers = [])
- {
- $this->bodyFormat = 'multipart';
- $this->options = array_filter([
- 'name' => $name,
- 'contents' => $contents,
- 'headers' => $headers,
- 'filename' => $filename,
- ]);
- return $this;
- }
- public function withMiddleware(callable $middleware)
- {
- $this->handlerStack->push($middleware);
- $this->options['handler'] = $this->handlerStack;
- return $this;
- }
- public function withRequestMiddleware(callable $middleware)
- {
- $this->handlerStack->push(Middleware::mapRequest($middleware));
- $this->options['handler'] = $this->handlerStack;
- return $this;
- }
- public function withResponseMiddleware(callable $middleware)
- {
- $this->handlerStack->push(Middleware::mapResponse($middleware));
- $this->options['handler'] = $this->handlerStack;
- return $this;
- }
- public function withHost(string $host)
- {
- $this->options['base_uri'] = $host;
- return $this;
- }
- public function withOptions(array $options)
- {
- unset($this->options[$this->bodyFormat], $this->options['body']);
- $this->options = array_merge_recursive($this->options, $options);
- return $this;
- }
- public function withCert(string $path, string $password)
- {
- $this->options['cert'] = [$path, $password];
- return $this;
- }
- public function withHeaders(array $headers)
- {
- $this->options = array_merge_recursive($this->options, [
- 'headers' => $headers,
- ]);
- return $this;
- }
- public function withBody($content, $contentType = 'application/json')
- {
- $this->bodyFormat = 'body';
- $this->options['headers']['Content-Type'] = $contentType;
- $this->pendingBody = $content;
- return $this;
- }
- public function withBasicAuth(string $username, string $password)
- {
- $this->options['auth'] = [$username, $password];
- return $this;
- }
- public function withDigestAuth(string $username, string $password)
- {
- $this->options['auth'] = [$username, $password, 'digest'];
- return $this;
- }
- public function withUA(string $ua)
- {
- $this->options['headers']['User-Agent'] = trim($ua);
- return $this;
- }
- public function withToken(string $token, string $type = 'Bearer')
- {
- $this->options['headers']['Authorization'] = trim($type . ' ' . $token);
- return $this;
- }
- public function withCookies(array $cookies, string $domain)
- {
- $this->options = array_merge_recursive($this->options, [
- 'cookies' => CookieJar::fromArray($cookies, $domain),
- ]);
- return $this;
- }
- public function withProxy($proxy)
- {
- $this->options['proxy'] = $proxy;
- return $this;
- }
- public function withVersion($version)
- {
- $this->options['version'] = $version;
- return $this;
- }
- public function maxRedirects(int $max)
- {
- $this->options['allow_redirects']['max'] = $max;
- return $this;
- }
- public function withRedirect($redirect = false)
- {
- $this->options['allow_redirects'] = $redirect;
- return $this;
- }
- public function withVerify($verify = false)
- {
- $this->options['verify'] = $verify;
- return $this;
- }
- public function withStream($boolean = false)
- {
- $this->options['stream'] = $boolean;
- return $this;
- }
- public function concurrency(int $times)
- {
- $this->concurrency = $times;
- return $this;
- }
- public function retry(int $retries = 1, int $sleep = 0)
- {
- $this->handlerStack->push((new Retry())->handle($retries, $sleep));
- $this->options['handler'] = $this->handlerStack;
- return $this;
- }
- public function delay(int $seconds)
- {
- $this->options['delay'] = $seconds * 1000;
- return $this;
- }
- public function timeout(float $seconds)
- {
- $this->options['timeout'] = $seconds;
- return $this;
- }
- public function connectTimeout(float $seconds)
- {
- $this->options['connect_timeout'] = $seconds;
- return $this;
- }
- /**
- * @param string|resource $to
- * @return $this
- */
- public function sink($to)
- {
- $this->options['sink'] = $to;
- return $this;
- }
- public function removeBodyFormat()
- {
- $this->isRemoveBodyFormat = true;
- return $this;
- }
- public function debug($class)
- {
- $logger = new Logger(function ($level, $message, array $context) use ($class) {
- $class::log($level, $message);
- }, function ($request, $response, $reason) {
- $requestBody = $request->getBody();
- $requestBody->rewind();
- //请求头
- $requestHeaders = [];
- foreach ((array)$request->getHeaders() as $k => $vs) {
- foreach ($vs as $v) {
- $requestHeaders[] = "$k: $v";
- }
- }
- //响应头
- $responseHeaders = [];
- foreach ((array)$response->getHeaders() as $k => $vs) {
- foreach ($vs as $v) {
- $responseHeaders[] = "$k: $v";
- }
- }
- $uri = $request->getUri();
- $path = $uri->getPath();
- if ($query = $uri->getQuery()) {
- $path .= '?' . $query;
- }
- return sprintf(
- "Request %s\n%s %s HTTP/%s\r\n%s\r\n\r\n%s\r\n--------------------\r\nHTTP/%s %s %s\r\n%s\r\n\r\n%s",
- $uri,
- $request->getMethod(),
- $path,
- $request->getProtocolVersion(),
- join("\r\n", $requestHeaders),
- $requestBody->getContents(),
- $response->getProtocolVersion(),
- $response->getStatusCode(),
- $response->getReasonPhrase(),
- join("\r\n", $responseHeaders),
- $response->getBody()->getContents()
- );
- });
- $this->handlerStack->push($logger);
- $this->options['handler'] = $this->handlerStack;
- return $this;
- }
- public function attach(string $name, string $contents, string $filename = null, array $headers = [])
- {
- $this->options['multipart'] = array_filter([
- 'name' => $name,
- 'contents' => $contents,
- 'headers' => $headers,
- 'filename' => $filename,
- ]);
- return $this;
- }
- public function get(string $url, array $query = [])
- {
- $params = parse_url($url, PHP_URL_QUERY);
- parse_str($params ?: '', $result);
- $this->options['query'] = array_merge($result, $query);
- return $this->request('GET', $url, $query);
- }
- public function post(string $url, array $data = [])
- {
- $this->options[$this->bodyFormat] = $data;
- return $this->request('POST', $url, $data);
- }
- public function patch(string $url, array $data = [])
- {
- $this->options[$this->bodyFormat] = $data;
- return $this->request('PATCH', $url, $data);
- }
- public function put(string $url, array $data = [])
- {
- $this->options[$this->bodyFormat] = $data;
- return $this->request('PUT', $url, $data);
- }
- public function delete(string $url, array $data = [])
- {
- $this->options[$this->bodyFormat] = $data;
- return $this->request('DELETE', $url, $data);
- }
- public function head(string $url, array $data = [])
- {
- $this->options[$this->bodyFormat] = $data;
- return $this->request('HEAD', $url, $data);
- }
- public function options(string $url, array $data = [])
- {
- $this->options[$this->bodyFormat] = $data;
- return $this->request('OPTIONS', $url, $data);
- }
- public function getAsync(string $url, $query = null, callable $success = null, callable $fail = null)
- {
- is_callable($query) || $this->options['query'] = $query;
- return $this->requestAsync('GET', $url, $query, $success, $fail);
- }
- public function postAsync(string $url, $data = null, callable $success = null, callable $fail = null)
- {
- is_callable($data) || $this->options[$this->bodyFormat] = $data;
- return $this->requestAsync('POST', $url, $data, $success, $fail);
- }
- public function patchAsync(string $url, $data = null, callable $success = null, callable $fail = null)
- {
- is_callable($data) || $this->options[$this->bodyFormat] = $data;
- return $this->requestAsync('PATCH', $url, $data, $success, $fail);
- }
- public function putAsync(string $url, $data = null, callable $success = null, callable $fail = null)
- {
- is_callable($data) || $this->options[$this->bodyFormat] = $data;
- return $this->requestAsync('PUT', $url, $data, $success, $fail);
- }
- public function deleteAsync(string $url, $data = null, callable $success = null, callable $fail = null)
- {
- is_callable($data) || $this->options[$this->bodyFormat] = $data;
- return $this->requestAsync('DELETE', $url, $data, $success, $fail);
- }
- public function headAsync(string $url, $data = null, callable $success = null, callable $fail = null)
- {
- is_callable($data) || $this->options[$this->bodyFormat] = $data;
- return $this->requestAsync('HEAD', $url, $data, $success, $fail);
- }
- public function optionsAsync(string $url, $data = null, callable $success = null, callable $fail = null)
- {
- is_callable($data) || $this->options[$this->bodyFormat] = $data;
- return $this->requestAsync('OPTIONS', $url, $data, $success, $fail);
- }
- public function multiAsync(array $promises, callable $success = null, callable $fail = null)
- {
- $count = count($promises);
- $this->concurrency = $this->concurrency ?: $count;
- $requests = function () use ($promises) {
- foreach ($promises as $promise) {
- yield function () use ($promise) {
- return $promise;
- };
- }
- };
- $fulfilled = function ($response, $index) use ($success) {
- if (!is_null($success)) {
- $response = $this->response($response);
- call_user_func_array($success, [$response, $index]);
- }
- };
- $rejected = function ($exception, $index) use ($fail) {
- if (!is_null($fail)) {
- $exception = $this->exception($exception);
- call_user_func_array($fail, [$exception, $index]);
- }
- };
- $pool = new Pool($this->client, $requests(), [
- 'concurrency' => $this->concurrency,
- 'fulfilled' => $fulfilled,
- 'rejected' => $rejected,
- ]);
- $pool->promise();
- return $pool;
- }
- protected function request(string $method, string $url, array $options = [])
- {
- if (isset($this->options[$this->bodyFormat])) {
- $this->options[$this->bodyFormat] = $options;
- } else {
- $this->options[$this->bodyFormat] = $this->pendingBody;
- }
- if ($this->isRemoveBodyFormat) {
- unset($this->options[$this->bodyFormat]);
- }
- try {
- $response = $this->client->request($method, $url, $this->options);
- return $this->response($response);
- } catch (ConnectException $e) {
- throw new ConnectionException($e->getMessage(), 0, $e);
- }
- }
- /**
- * 原生请求
- * @param string $method
- * @param string $url
- * @param array $options
- * @return Response
- * @throws ConnectionException
- * @throws \GuzzleHttp\Exception\GuzzleException
- */
- public function client(string $method, string $url, array $options = [])
- {
- if (isset($this->options[$this->bodyFormat])) {
- $this->options[$this->bodyFormat] = $options;
- } else {
- $this->options[$this->bodyFormat] = $this->pendingBody;
- }
- if ($this->isRemoveBodyFormat) {
- unset($this->options[$this->bodyFormat]);
- }
- try {
- if (empty($options)) {
- $options = $this->options;
- }
- $response = $this->client->request($method, $url, $options);
- return $this->response($response);
- } catch (ConnectException $e) {
- throw new ConnectionException($e->getMessage(), 0, $e);
- }
- }
- /**
- * 原生异步请求
- * @param string $method
- * @param string $url
- * @param array $options
- * @return Response
- * @throws ConnectionException
- */
- public function clientAsync(string $method, string $url, array $options = [])
- {
- if (isset($this->options[$this->bodyFormat])) {
- $this->options[$this->bodyFormat] = $options;
- } else {
- $this->options[$this->bodyFormat] = $this->pendingBody;
- }
- if ($this->isRemoveBodyFormat) {
- unset($this->options[$this->bodyFormat]);
- }
- try {
- if (empty($options)) {
- $options = $this->options;
- }
- $response = $this->client->requestAsync($method, $url, $options);
- return $this->response($response);
- } catch (ConnectException $e) {
- throw new ConnectionException($e->getMessage(), 0, $e);
- }
- }
- protected function requestAsync(string $method, string $url, $options = null, callable $success = null, callable $fail = null)
- {
- if (is_callable($options)) {
- $successCallback = $options;
- $failCallback = $success;
- } else {
- $successCallback = $success;
- $failCallback = $fail;
- }
- if (isset($this->options[$this->bodyFormat])) {
- $this->options[$this->bodyFormat] = $options;
- } else {
- $this->options[$this->bodyFormat] = $this->pendingBody;
- }
- if ($this->isRemoveBodyFormat) {
- unset($this->options[$this->bodyFormat]);
- }
- try {
- $promise = $this->client->requestAsync($method, $url, $this->options);
- $fulfilled = function ($response) use ($successCallback) {
- if (!is_null($successCallback)) {
- $response = $this->response($response);
- call_user_func_array($successCallback, [$response]);
- }
- };
- $rejected = function ($exception) use ($failCallback) {
- if (!is_null($failCallback)) {
- $exception = $this->exception($exception);
- call_user_func_array($failCallback, [$exception]);
- }
- };
- $promise->then($fulfilled, $rejected);
- $this->promises[] = $promise;
- return $promise;
- } catch (ConnectException $e) {
- throw new ConnectionException($e->getMessage(), 0, $e);
- }
- }
- public function wait()
- {
- if (!empty($this->promises)) {
- \GuzzleHttp\Promise\Utils($this->promises)->wait();
- }
- $this->promises = [];
- }
- protected function response($response)
- {
- return new Response($response);
- }
- protected function exception($exception)
- {
- return new RequestException($exception);
- }
- }
|