Added HttpClient

This commit is contained in:
Netkas 2022-12-09 00:25:41 -05:00
parent dbf0109700
commit 4f9f78e21d
7 changed files with 390 additions and 1 deletions

View file

@ -268,6 +268,11 @@
*/ */
const MissingDependencyException = -1751; const MissingDependencyException = -1751;
/**
* @see HttpException
*/
const HttpException = -1752;
/** /**
* All the exception codes from NCC * All the exception codes from NCC
*/ */
@ -322,6 +327,7 @@
self::ComposerNotAvailableException, self::ComposerNotAvailableException,
self::ComposerException, self::ComposerException,
self::UserAbortedOperationException, self::UserAbortedOperationException,
self::MissingDependencyException self::MissingDependencyException,
self::HttpException
]; ];
} }

View file

@ -0,0 +1,11 @@
<?php
namespace ncc\Abstracts;
abstract class HttpRequestType
{
const GET = 'GET';
const POST = 'POST';
const PUT = 'PUT';
const DELETE = 'DELETE';
}

View file

@ -0,0 +1,104 @@
<?php
namespace ncc\Abstracts;
abstract class HttpStatusCodes
{
const OK = 200;
const CREATED = 201;
const ACCEPTED = 202;
const NO_CONTENT = 204;
const MOVED_PERMANENTLY = 301;
const FOUND = 302;
const SEE_OTHER = 303;
const NOT_MODIFIED = 304;
const TEMPORARY_REDIRECT = 307;
const PERMANENT_REDIRECT = 308;
const BAD_REQUEST = 400;
const UNAUTHORIZED = 401;
const FORBIDDEN = 403;
const NOT_FOUND = 404;
const METHOD_NOT_ALLOWED = 405;
const NOT_ACCEPTABLE = 406;
const REQUEST_TIMEOUT = 408;
const CONFLICT = 409;
const GONE = 410;
const LENGTH_REQUIRED = 411;
const PRECONDITION_FAILED = 412;
const PAYLOAD_TOO_LARGE = 413;
const URI_TOO_LONG = 414;
const UNSUPPORTED_MEDIA_TYPE = 415;
const RANGE_NOT_SATISFIABLE = 416;
const EXPECTATION_FAILED = 417;
const IM_A_TEAPOT = 418;
const MISDIRECTED_REQUEST = 421;
const UNPROCESSABLE_ENTITY = 422;
const LOCKED = 423;
const FAILED_DEPENDENCY = 424;
const UPGRADE_REQUIRED = 426;
const PRECONDITION_REQUIRED = 428;
const TOO_MANY_REQUESTS = 429;
const REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
const UNAVAILABLE_FOR_LEGAL_REASONS = 451;
const INTERNAL_SERVER_ERROR = 500;
const NOT_IMPLEMENTED = 501;
const BAD_GATEWAY = 502;
const SERVICE_UNAVAILABLE = 503;
const GATEWAY_TIMEOUT = 504;
const HTTP_VERSION_NOT_SUPPORTED = 505;
const VARIANT_ALSO_NEGOTIATES = 506;
const INSUFFICIENT_STORAGE = 507;
const LOOP_DETECTED = 508;
const NOT_EXTENDED = 510;
const NETWORK_AUTHENTICATION_REQUIRED = 511;
const All = [
self::OK,
self::CREATED,
self::ACCEPTED,
self::NO_CONTENT,
self::MOVED_PERMANENTLY,
self::FOUND,
self::SEE_OTHER,
self::NOT_MODIFIED,
self::TEMPORARY_REDIRECT,
self::PERMANENT_REDIRECT,
self::BAD_REQUEST,
self::UNAUTHORIZED,
self::FORBIDDEN,
self::NOT_FOUND,
self::METHOD_NOT_ALLOWED,
self::NOT_ACCEPTABLE,
self::REQUEST_TIMEOUT,
self::CONFLICT,
self::GONE,
self::LENGTH_REQUIRED,
self::PRECONDITION_FAILED,
self::PAYLOAD_TOO_LARGE,
self::URI_TOO_LONG,
self::UNSUPPORTED_MEDIA_TYPE,
self::RANGE_NOT_SATISFIABLE,
self::EXPECTATION_FAILED,
self::IM_A_TEAPOT,
self::MISDIRECTED_REQUEST,
self::UNPROCESSABLE_ENTITY,
self::LOCKED,
self::FAILED_DEPENDENCY,
self::UPGRADE_REQUIRED,
self::PRECONDITION_REQUIRED,
self::TOO_MANY_REQUESTS,
self::REQUEST_HEADER_FIELDS_TOO_LARGE,
self::UNAVAILABLE_FOR_LEGAL_REASONS,
self::INTERNAL_SERVER_ERROR,
self::NOT_IMPLEMENTED,
self::BAD_GATEWAY,
self::SERVICE_UNAVAILABLE,
self::GATEWAY_TIMEOUT,
self::HTTP_VERSION_NOT_SUPPORTED,
self::VARIANT_ALSO_NEGOTIATES,
self::INSUFFICIENT_STORAGE,
self::LOOP_DETECTED,
self::NOT_EXTENDED,
self::NETWORK_AUTHENTICATION_REQUIRED
];
}

View file

@ -0,0 +1,20 @@
<?php
namespace ncc\Exceptions;
use Exception;
use ncc\Abstracts\ExceptionCodes;
use Throwable;
class HttpException extends Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, ExceptionCodes::HttpException, $previous);
$this->message = $message;
}
}

View file

@ -0,0 +1,87 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects;
use ncc\Abstracts\HttpRequestType;
class HttpRequest
{
/**
* The HTTP request type.
*
* @var string|HttpRequestType
*/
public $Type;
/**
* The URL to send the request to.
*
* @var string
*/
public $Url;
/**
* The headers to send with the request.
*
* @var array
*/
public $Headers;
/**
* The body to send with the request.
*
* @var string|null
*/
public $Body;
/**
* The authentication username or password to send with the request.
*
* @var array|string
*/
public $Authentication;
public function __construct()
{
$this->Type = HttpRequestType::GET;
$this->Body = null;
$this->Headers = [
'User-Agent: ncc/1.0'
];
}
/**
* Returns an array representation of the object.
*
* @return array
*/
public function toArray(): array
{
return [
'type' => $this->Type,
'url' => $this->Url,
'headers' => $this->Headers,
'body' => $this->Body,
'authentication' => $this->Authentication
];
}
/**
* Constructs a new HttpRequest object from an array representation.
*
* @param array $data
* @return static
*/
public static function fromArray(array $data): self
{
$request = new self();
$request->Type = $data['type'];
$request->Url = $data['url'];
$request->Headers = $data['headers'];
$request->Body = $data['body'];
$request->Authentication = $data['authentication'];
return $request;
}
}

View file

@ -0,0 +1,50 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Objects;
class HttpResponse
{
/**
* The HTTP status code.
*
* @var int
*/
public $StatusCode;
/**
* The headers returned by the server.
*
* @var array
*/
public $Headers;
/**
* The body returned by the server.
*
* @var string
*/
public $Body;
public function __construct()
{
$this->StatusCode = 0;
$this->Headers = [];
$this->Body = '';
}
/**
* Returns an array representation of the object.
*
* @return array
*/
public function toArray(): array
{
return [
'status_code' => $this->StatusCode,
'headers' => $this->Headers,
'body' => $this->Body
];
}
}

View file

@ -0,0 +1,111 @@
<?php
namespace ncc\Utilities;
use ncc\Abstracts\HttpRequestType;
use ncc\Exceptions\HttpException;
use ncc\Objects\HttpRequest;
use ncc\Objects\HttpResponse;
class HttpClient
{
/**
* Creates a new HTTP request and returns the response.
*
* @param HttpRequest $httpRequest
* @return HttpResponse
* @throws HttpException
*/
public static function request(HttpRequest $httpRequest): HttpResponse
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $httpRequest->Url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_MAXREDIRS, 10);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
switch($httpRequest->Type)
{
case HttpRequestType::GET:
curl_setopt($curl, CURLOPT_HTTPGET, true);
break;
case HttpRequestType::POST:
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $httpRequest->Body);
break;
case HttpRequestType::PUT:
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($curl, CURLOPT_POSTFIELDS, $httpRequest->Body);
break;
case HttpRequestType::DELETE:
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
break;
default:
throw new HttpException(sprintf('Invalid HTTP request type: %s', $httpRequest->Type));
}
if (is_array($httpRequest->Authentication))
{
curl_setopt($curl, CURLOPT_USERPWD, $httpRequest->Authentication[0] . ':' . $httpRequest->Authentication[1]);
}
else if (is_string($httpRequest->Authentication))
{
curl_setopt($curl, CURLOPT_USERPWD, $httpRequest->Authentication);
}
if (count($httpRequest->Headers) > 0)
curl_setopt($curl, CURLOPT_HTTPHEADER, $httpRequest->Headers);
$response = curl_exec($curl);
if ($response === false)
{
$error = curl_error($curl);
curl_close($curl);
throw new HttpException($error);
}
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);
$httpResponse = new HttpResponse();
$httpResponse->StatusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$httpResponse->Headers = self::parseHeaders($headers);
$httpResponse->Body = $body;
curl_close($curl);
return $httpResponse;
}
/**
* Takes the return headers of a cURL request and parses them into an array.
*
* @param string $headers
* @return array
*/
private static function parseHeaders(string $headers): array
{
$headers = explode("\r", $headers);
$headers = array_filter($headers, function ($header)
{
return !empty($header);
});
$headers = array_map(function ($header) {
return explode(':', $header, 2);
}, $headers);
return array_combine(array_map(function ($header) { return strtolower($header[0]); }, $headers),
array_map(function ($header) { return trim($header[1]); }, $headers)
);
}
}