<?php
namespace Yurun\Util;
use Yurun\Util\YurunHttp\Attributes;
use Yurun\Util\YurunHttp\Http\Request;
use Yurun\Util\YurunHttp\Http\Psr7\UploadedFile;
use Yurun\Util\YurunHttp\Http\Psr7\Consts\MediaType;
class HttpRequest
{
private $handler;
public $url;
public $content;
public $options =[];
public $headers =[];
public $cookies =[];
public $retry = 0;
public $useProxy = false;
public $proxy =[];
public $isVerifyCA = false;
public $caCert;
public $connectTimeout = 30000;
public $timeout = 30000;
public $downloadSpeed;
public $uploadSpeed;
public $username;
public $password;
public $saveFileOption =[];
public $followLocation = true;
public $maxRedirects = 10;
public $certType = 'pem';
public $certPath = '';
public $certPassword = null;
public $keyType = 'pem';
public $keyPath = '';
public $keyPassword = null;
public $method = 'GET';
public $protocolVersion = '1.1';
public static $proxyAuths =[];
public static $proxyType =[];
public function __construct()
{
$this->open();
}
public function __destruct()
{
$this->close();
}
public function open()
{
$this->handler = YurunHttp::getHandler();
$this->retry = 0;
$this->headers = $this->options =[];
$this->url = $this->content = '';
$this->useProxy = false;
$this->proxy = [
'auth' => 'basic',
'type' => 'http',
];
$this->isVerifyCA = false;
$this->caCert = null;
$this->connectTimeout = 30000;
$this->timeout = 30000;
$this->downloadSpeed = null;
$this->uploadSpeed = null;
$this->username = null;
$this->password = null;
$this->saveFileOption =[];
}
public function close()
{
$this->handler->close();
$this->handler = null;
}
public static function newSession()
{
return new static;
}
public function getHandler()
{
return $this->handler;
}
public function url($url)
{
$this->url = $url;
return $this;
}
public function content($content)
{
return $this->requestBody($content);
}
public function params($params)
{
return $this->requestBody($params);
}
public function requestBody($requestBody)
{
$this->content = $requestBody;
return $this;
}
public function options($options)
{
foreach($options as $key => $value)
{
$this->options[$key] = $value;
}
return $this;
}
public function option($option, $value)
{
$this->options[$option] = $value;
return $this;
}
public function headers($headers)
{
$this->headers = array_merge($this->headers, $headers);
return $this;
}
public function header($header, $value)
{
$this->headers[$header] = $value;
return $this;
}
public function accept($accept)
{
$this->headers['Accept'] = $accept;
return $this;
}
public function acceptLanguage($acceptLanguage)
{
$this->headers['Accept-Language'] = $acceptLanguage;
return $this;
}
public function acceptEncoding($acceptEncoding)
{
$this->headers['Accept-Encoding'] = $acceptEncoding;
return $this;
}
public function acceptRanges($acceptRanges)
{
$this->headers['Accept-Ranges'] = $acceptRanges;
return $this;
}
public function cacheControl($cacheControl)
{
$this->headers['Cache-Control'] = $cacheControl;
return $this;
}
public function cookies($cookies)
{
$this->cookies = array_merge($this->cookies, $cookies);
return $this;
}
public function cookie($name, $value)
{
$this->cookies[$name] = $value;
return $this;
}
public function contentType($contentType)
{
$this->headers['Content-Type'] = $contentType;
return $this;
}
public function range($range)
{
$this->headers['Range'] = $range;
return $this;
}
public function referer($referer)
{
$this->headers['Referer'] = $referer;
return $this;
}
public function userAgent($userAgent)
{
$this->headers['User-Agent'] = $userAgent;
return $this;
}
public function ua($userAgent)
{
return $this->userAgent($userAgent);
}
public function retry($retry)
{
$this->retry = $retry < 0 ? 0 : $retry; return $this;
}
public function proxy($server, $port, $type = 'http', $auth = 'basic')
{
$this->useProxy = true;
$this->proxy = [
'server' => $server,
'port' => $port,
'type' => $type,
'auth' => $auth,
];
return $this;
}
public function proxyAuth($username, $password)
{
$this->proxy['username'] = $username;
$this->proxy['password'] = $password;
}
public function timeout($timeout = null, $connectTimeout = null)
{
if(null !== $timeout)
{
$this->timeout = $timeout;
}
if(null !== $connectTimeout)
{
$this->connectTimeout = $connectTimeout;
}
return $this;
}
public function limitRate($download = 0, $upload = 0)
{
$this->downloadSpeed = $download;
$this->uploadSpeed = $upload;
return $this;
}
public function userPwd($username, $password)
{
$this->username = $username;
$this->password = $password;
return $this;
}
public function saveFile($filePath, $fileMode = 'w+')
{
$this->saveFileOption['filePath'] = $filePath;
$this->saveFileOption['fileMode'] = $fileMode;
return $this;
}
public function getSavePath()
{
return $this->saveFileOption['savePath'];
}
public function sslCert($path, $type = null, $password = null)
{
$this->certPath = $path;
if(null !== $type)
{
$this->certType = $type;
}
if(null !== $password)
{
$this->certPassword = $password;
}
return $this;
}
public function sslKey($path, $type = null, $password = null)
{
$this->keyPath = $path;
if(null !== $type)
{
$this->keyType = $type;
}
if(null !== $password)
{
$this->keyPassword = $password;
}
return $this;
}
public function method($method)
{
$this->method = $method;
return $this;
}
protected function parseRequestBody($requestBody, $contentType)
{
$body = $files = [];
if(is_string($requestBody))
{
$body = $requestBody;
}
else if(is_array($requestBody))
{
switch($contentType)
{
case 'json':
$body = json_encode($requestBody);
$this->header('Content-Type', MediaType::APPLICATION_JSON);
break;
default:
foreach($requestBody as $k => $v)
{
if($v instanceof UploadedFile)
{
$files[$k] = $v;
}
else
{
$body[$k] = $v;
}
}
$body = http_build_query($body, '', '&');
}
}
else
{
throw new \InvalidArgumentException('$requestBody only can be string or array');
}
return [$body, $files];
}
public function buildRequest($url = null, $requestBody = null, $method = null, $contentType = null)
{
if(null === $url)
{
$url = $this->url;
}
if(null === $method)
{
$method = $this->method;
}
list($body, $files) = $this->parseRequestBody(null === $requestBody ? $this->content : $requestBody, $contentType);
$request = new Request($url, $this->headers, $body, $method);
$request = $request->withUploadedFiles($files)
->withCookieParams($this->cookies)
->withAttribute('maxRedirects', $this->maxRedirects)
->withAttribute('isVerifyCA', $this->isVerifyCA)
->withAttribute('caCert', $this->caCert)
->withAttribute('certPath', $this->certPath)
->withAttribute('certPassword', $this->certPassword)
->withAttribute('certType', $this->certType)
->withAttribute('keyPath', $this->keyPath)
->withAttribute('keyPassword', $this->keyPassword)
->withAttribute('keyType', $this->keyType)
->withAttribute('options', $this->options)
->withAttribute('saveFilePath', isset($this->saveFileOption['filePath']) ? $this->saveFileOption['filePath'] : null)
->withAttribute('useProxy', $this->useProxy)
->withAttribute('username', $this->username)
->withAttribute('password', $this->password)
->withAttribute('connectTimeout', $this->connectTimeout)
->withAttribute('timeout', $this->timeout)
->withAttribute('downloadSpeed', $this->downloadSpeed)
->withAttribute('uploadSpeed', $this->uploadSpeed)
->withAttribute('followLocation', $this->followLocation)
->withProtocolVersion($this->protocolVersion)
;
foreach($this->proxy as $name => $value)
{
$request = $request->withAttribute('proxy.' . $name, $value);
}
return $request;
}
public function send($url = null, $requestBody = null, $method = null, $contentType = null)
{
$request = $this->buildRequest($url, $requestBody, $method, $contentType);
return YurunHttp::send($request, $this->handler);
}
public function sendHttp2WithoutRecv($url = null, $requestBody = null, $method = 'GET', $contentType = null)
{
$request = $this->buildRequest($url, $requestBody, $method, $contentType)
->withProtocolVersion('2.0')
->withAttribute(Attributes::HTTP2_NOT_RECV, true);
return YurunHttp::send($request, $this->handler);
}
public function get($url = null, $requestBody = null)
{
if(!empty($requestBody))
{
if(strpos($url, '?'))
{
$url .= '&';
}
else
{
$url .= '?';
}
$url .= http_build_query($requestBody, '', '&');
}
return $this->send($url,[], 'GET');
}
public function post($url = null, $requestBody = null, $contentType = null)
{
return $this->send($url, $requestBody, 'POST', $contentType);
}
public function head($url = null, $requestBody = null)
{
return $this->send($url, $requestBody, 'HEAD');
}
public function put($url = null, $requestBody = null, $contentType = null)
{
return $this->send($url, $requestBody, 'PUT', $contentType);
}
public function patch($url = null, $requestBody = null, $contentType = null)
{
return $this->send($url, $requestBody, 'PATCH', $contentType);
}
public function delete($url = null, $requestBody = null, $contentType = null)
{
return $this->send($url, $requestBody, 'DELETE', $contentType);
}
public function download($fileName, $url = null, $requestBody = null, $method = 'GET')
{
static $autoExtFlag = '.*';
if($isAutoExt = (substr($fileName, -strlen($autoExtFlag)) === $autoExtFlag))
{
$basename = substr($fileName, 0, -2);
$fileName = $basename . '.tmp';
}
$result = $this->saveFile($fileName)->send($url, $requestBody, $method);
if($isAutoExt)
{
$ext = MediaType::getExt($result->getHeaderLine('Content-Type'));
if(null === $ext)
{
$ext = 'file';
}
rename($fileName, $basename . '.' . $ext);
}
$this->saveFileOption =[];
return $result;
}
public function websocket($url = null)
{
$request = $this->buildRequest($url);
return YurunHttp::websocket($request, $this->handler);
}
}
if(extension_loaded('curl'))
{
HttpRequest::$proxyAuths = [
'basic' => CURLAUTH_BASIC,
'ntlm' => CURLAUTH_NTLM
];
HttpRequest::$proxyType = [
'http' => CURLPROXY_HTTP,
'socks4' => CURLPROXY_SOCKS4,
'socks4a' => 6, 'socks5' => CURLPROXY_SOCKS5,
];
}