From 85b59201e91aef966d23fd8f1de3e0d2464fa0a3 Mon Sep 17 00:00:00 2001 From: Julian Gojani Date: Wed, 24 Aug 2022 17:37:03 +0200 Subject: [PATCH] Initial --- .gitignore | 3 + README.md | 80 +++++++++++++++++++ autoload.php | 44 ++++++++++ composer.json | 19 +++++ .../ulole/httpclient/HttpClient.php | 67 ++++++++++++++++ .../ulole/httpclient/HttpRequest.php | 60 ++++++++++++++ .../ulole/httpclient/HttpResponse.php | 43 ++++++++++ .../httpclient/exceptions/HttpException.php | 9 +++ .../ulole/httpclient/http/CURLHttpAdapter.php | 60 ++++++++++++++ .../ulole/httpclient/http/HttpAdapter.php | 14 ++++ .../ulole/httpclient/traits/HasHeaders.php | 47 +++++++++++ .../httpclient/traits/HasQueryParameters.php | 29 +++++++ .../httpclient/traits/HasRequestSettings.php | 36 +++++++++ src/test/testbootstrap.php | 21 +++++ uppm.json | 18 +++++ uppm.locks.json | 12 +++ 16 files changed, 562 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 autoload.php create mode 100644 composer.json create mode 100644 src/main/de/interaapps/ulole/httpclient/HttpClient.php create mode 100644 src/main/de/interaapps/ulole/httpclient/HttpRequest.php create mode 100644 src/main/de/interaapps/ulole/httpclient/HttpResponse.php create mode 100644 src/main/de/interaapps/ulole/httpclient/exceptions/HttpException.php create mode 100644 src/main/de/interaapps/ulole/httpclient/http/CURLHttpAdapter.php create mode 100644 src/main/de/interaapps/ulole/httpclient/http/HttpAdapter.php create mode 100644 src/main/de/interaapps/ulole/httpclient/traits/HasHeaders.php create mode 100644 src/main/de/interaapps/ulole/httpclient/traits/HasQueryParameters.php create mode 100644 src/main/de/interaapps/ulole/httpclient/traits/HasRequestSettings.php create mode 100644 src/test/testbootstrap.php create mode 100644 uppm.json create mode 100644 uppm.locks.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33671da --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.idea +/modules +.fuse_* \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..22439b3 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# Ulole HTTP Client `1.0` +## Installation +Module +#### UPPM +``` +uppm i interaapps/ulole-http-client +``` +#### Composer +``` +composer require interaapps/ulole-http-client +``` + +## Getting started +```php +$client = new HttpClient("https://ping.intera.dev"); + +$authors = $client->get("/authors") + ->send() + ->json(); + +foreach ($authors as $author) { + echo $author->name . "\n"; +} + +$success = $client->post("/authors", [ + "name" => "Author" +]) + ->bearer("HelloWorld") + ->send() + ->ok(); + +if ($success) { + echo "Done!"; +} + + + +``` + + +## Request-Settings +On a HttpRequest or for all HttpRequests on the HttpClient you can use some methods which will change some request options. +```php + +$request = $client->get("https://google.com"); + +$request->header("X-Header", "Value"); +$request->bearer("ABCDE"); + +// Set Query Parameter +$request->query("key", "value"); + +// Set Body +$request->body("this-is-the-body=yey"); + +// Set Json Body +$request->json(["hello" => "world"]); + + +$request->timeout(150); + +$request->followRedirects(); +$request->notFollowRedirects(); + + +$request->formData([ + "file" => new CURLFile("file.txt") +]); + +$response = $request->send(); + +var_dump($response->json()); +// From json model +var_dump($response->json(User::class)); + +var_dump($response->header("content-type")); +var_dump($response->body()); +var_dump($response->status()); +var_dump($response->ok()); +``` \ No newline at end of file diff --git a/autoload.php b/autoload.php new file mode 100644 index 0000000..7a8f3bd --- /dev/null +++ b/autoload.php @@ -0,0 +1,44 @@ +namespace_bindings)) + $uppmlock->namespaceBindings = $uppmlock->namespace_bindings; + if (isset($uppmlock->directnamespaces)) + $uppmlock->directNamespaceBindings = $uppmlock->directnamespaces; + } + + spl_autoload_register(function($class) use ($dir, $mod, $uppmlock) { + if (isset($uppmlock->directNamespaceBindings->{$class})) + @include_once "$dir/".str_replace("\\","/",$uppmlock->directNamespaceBindings->{$class}); + else if(file_exists("$dir/".str_replace("\\","/",$class).".php")) + @include_once "$dir/".str_replace("\\","/",$class).".php"; + else if(file_exists("$dir/modules/".str_replace("\\","/",$class).".php")) + @include_once "$dir/modules/".str_replace("\\","/",$class).".php"; + else if(file_exists("$dir/src/".str_replace("\\","/",$class).".php")) + @include_once "$dir/src/".str_replace("\\","/",$class).".php"; + else if(file_exists("$dir/src/$mod/".str_replace("\\","/",$class).".php")) + @include_once "$dir/src/$mod/".str_replace("\\","/",$class).".php"; + else if(isset($uppmlock->namespaceBindings)) { + foreach ($uppmlock->namespaceBindings as $namespaceBinding => $folder){ + if (substr($class, 0, strlen($namespaceBinding)) === $namespaceBinding) { + $splitClass = explode($namespaceBinding."\\", $class, 2); + if (isset($splitClass[1]) && $splitClass[1] != "") + $class = $splitClass[1]; + $classFile = $folder.'/'.str_replace("\\","/", $class).".php"; + if (file_exists($dir."/".$classFile)) { + @include_once $dir."/".$classFile; + break; + } + } + } + } + }); + + if (isset($uppmlock->initscripts)) + foreach ($uppmlock->initscripts as $script) { + @include_once $script; + } + +}; \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f0d7af7 --- /dev/null +++ b/composer.json @@ -0,0 +1,19 @@ +{ + "name": "interaapps/ulole-http-client", + "version": "1.0.0", + "type": "library", + "authors": [ + { + "name": "JulianFun123", + "email": "julian@gojani.xyz" + } + ], + "require": { + "php": ">=8.0" + }, + "autoload": { + "psr-4": { + "de\\interaapps\\ulole\\module\\": "src/main/de/interaapps/ulole/httpclient" + } + } +} diff --git a/src/main/de/interaapps/ulole/httpclient/HttpClient.php b/src/main/de/interaapps/ulole/httpclient/HttpClient.php new file mode 100644 index 0000000..6056283 --- /dev/null +++ b/src/main/de/interaapps/ulole/httpclient/HttpClient.php @@ -0,0 +1,67 @@ +adapter = HttpClient::$adapterDefault; + $this->jsonPlus = HttpClient::$jsonPlusDefault; + + $req = new HttpRequest($this, $this->baseUrl . $method, $url); + $req->headers($this->headers); + $req->queries($this->queryParameters); + $req->timeout($this->timeout); + return $req; + } + + public function get(string $url, array|null $query = null): HttpRequest { + return $this->request("GET", $url)->queries($query); + } + + public function delete(string $url, array|null $query = null): HttpRequest { + return $this->request("DELETE", $url)->queries($query); + } + + public function head(string $url, array|null $query = null): HttpRequest { + return $this->request("HEAD", $url)->queries($query); + } + + public function post(string $url, mixed $body = null): HttpRequest { + return $this->request("POST", $url)->json($body); + } + + public function put(string $url, mixed $body = null): HttpRequest { + return $this->request("POST", $url)->json($body); + } + + public function patch(string $url, mixed $body = null): HttpRequest { + return $this->request("PATCH", $url)->json($body); + } + + public function getAdapter(): HttpAdapter { + return $this->adapter; + } + + public function getJsonPlus(): JSONPlus { + return $this->jsonPlus; + } +} + +HttpClient::$adapterDefault = new CURLHttpAdapter(); +HttpClient::$jsonPlusDefault = JSONPlus::$default; \ No newline at end of file diff --git a/src/main/de/interaapps/ulole/httpclient/HttpRequest.php b/src/main/de/interaapps/ulole/httpclient/HttpRequest.php new file mode 100644 index 0000000..194bd5a --- /dev/null +++ b/src/main/de/interaapps/ulole/httpclient/HttpRequest.php @@ -0,0 +1,60 @@ +url; + if (count($this->queryParameters) > 0) + $this->url .= '?' . http_build_query($this->queryParameters); + $res = $this->client->getAdapter()->do($this->client, $this); + $this->url = $url; + return $res; + } + + + public function getMethod(): string { + return $this->method; + } + + public function getUrl(): string { + return $this->url; + } + + public function body(mixed $body): HttpRequest { + $this->body = $body; + return $this; + } + + public function formData(array $postFields): HttpRequest { + $this->body = $postFields; + $this->header("Content-Type", "multipart/form-data"); + return $this; + } + + public function json(mixed $m): HttpRequest { + $this->body = $this->client->getJsonPlus()->toJson($m); + $this->header("Content-Type", "application/json"); + return $this; + } + + public function getBody(): mixed { + return $this->body; + } + +} \ No newline at end of file diff --git a/src/main/de/interaapps/ulole/httpclient/HttpResponse.php b/src/main/de/interaapps/ulole/httpclient/HttpResponse.php new file mode 100644 index 0000000..ebc02b9 --- /dev/null +++ b/src/main/de/interaapps/ulole/httpclient/HttpResponse.php @@ -0,0 +1,43 @@ +body; + } + + public function json(string|null $type = null): mixed { + return $this->client->getJsonPlus()->fromJson($this->body(), $type); + } + + public function status(): int { + return $this->status; + } + + + public function ok(): bool { + return $this->status >= 200 && $this->status < 400; + } + + public function header(string $key): mixed { + return $this->headers[$key]; + } + + public function headers(): array { + return $this->headers; + } + + public function getClient(): HttpClient { + return $this->client; + } +} \ No newline at end of file diff --git a/src/main/de/interaapps/ulole/httpclient/exceptions/HttpException.php b/src/main/de/interaapps/ulole/httpclient/exceptions/HttpException.php new file mode 100644 index 0000000..c2c135c --- /dev/null +++ b/src/main/de/interaapps/ulole/httpclient/exceptions/HttpException.php @@ -0,0 +1,9 @@ +getUrl()); + curl_setopt($curlReq, CURLOPT_CUSTOMREQUEST, $request->getMethod()); + curl_setopt($curlReq, CURLOPT_RETURNTRANSFER, true); + + if ($request->getTimeout() !== null) + curl_setopt($curlReq, CURLOPT_TIMEOUT_MS, $request->getTimeout()); + + curl_setopt($curlReq, CURLOPT_FOLLOWLOCATION, $request->isFollowingRedirects()); + + $headers = []; + foreach ($request->getHeaders() as $key => $val) { + $headers[] = "$key: $val"; + } + + curl_setopt($curlReq, CURLOPT_HTTPHEADER, $headers); + + if ($request->getBody() !== null && in_array($request->getMethod(), ["POST", "PUT", "PATCH"])) { + curl_setopt($curlReq, CURLOPT_POSTFIELDS, $request->getBody()); + } + + $headers = []; + curl_setopt($curlReq, CURLOPT_HEADERFUNCTION, + function($curl, $header) use (&$headers) { + $len = strlen($header); + $header = explode(':', $header, 2); + if (count($header) < 2) + return $len; + $headers[strtolower(trim($header[0]))] = trim($header[1]); + return $len; + } + ); + + + $body = curl_exec($curlReq); + if ($body === false) + throw new HttpException(curl_error($curlReq)); + + curl_close($curlReq); + + $status = curl_getinfo($curlReq, CURLINFO_HTTP_CODE); + + return new HttpResponse($client, $status, $body, $headers); + } +} \ No newline at end of file diff --git a/src/main/de/interaapps/ulole/httpclient/http/HttpAdapter.php b/src/main/de/interaapps/ulole/httpclient/http/HttpAdapter.php new file mode 100644 index 0000000..e56efcd --- /dev/null +++ b/src/main/de/interaapps/ulole/httpclient/http/HttpAdapter.php @@ -0,0 +1,14 @@ +headers; + } + + public function header(string $key, string $headers): static { + $this->headers[$key] = $headers; + return $this; + } + + public function headers(array|null $headers): static { + if ($headers === null) + return $this; + + foreach ($headers as $key => $value) { + $this->header($key, $value); + } + return $this; + } + + public function setHeaders(array $headers): void { + $this->headers = $headers; + } + + public function getHeader(string $key): string { + return $this->headers[$key]; + } + + public function contentType(string $type): static { + return $this->authorization("Content-Type", $type); + } + + public function authorization(string $type, string $token): static { + return $this->header("Authorization", "$type $token"); + } + + public function bearer(string $token): static { + return $this->authorization("Bearer", $token); + } +} \ No newline at end of file diff --git a/src/main/de/interaapps/ulole/httpclient/traits/HasQueryParameters.php b/src/main/de/interaapps/ulole/httpclient/traits/HasQueryParameters.php new file mode 100644 index 0000000..376e9c3 --- /dev/null +++ b/src/main/de/interaapps/ulole/httpclient/traits/HasQueryParameters.php @@ -0,0 +1,29 @@ +queryParameters[$key] = $query; + return $this; + } + + public function queries(array|null $queries): static { + if ($queries === null) + return $this; + + foreach ($queries as $key => $value) { + $this->query($key, $value); + } + return $this; + } + + public function getQueryParameters(): array { + return $this->queryParameters; + } + + public function setQueryParameters(array $queryParameters): void { + $this->queryParameters = $queryParameters; + } +} \ No newline at end of file diff --git a/src/main/de/interaapps/ulole/httpclient/traits/HasRequestSettings.php b/src/main/de/interaapps/ulole/httpclient/traits/HasRequestSettings.php new file mode 100644 index 0000000..164351a --- /dev/null +++ b/src/main/de/interaapps/ulole/httpclient/traits/HasRequestSettings.php @@ -0,0 +1,36 @@ +timeout = $timeout; + return $this; + } + + public function getTimeout(): ?int { + return $this->timeout; + } + + public function followRedirects(): static { + $this->followRedirects = true; + return $this; + } + + public function notFollowRedirects(): static { + $this->followRedirects = false; + return $this; + } + + public function isFollowingRedirects(): bool { + return $this->followRedirects; + } + + +} \ No newline at end of file diff --git a/src/test/testbootstrap.php b/src/test/testbootstrap.php new file mode 100644 index 0000000..8434091 --- /dev/null +++ b/src/test/testbootstrap.php @@ -0,0 +1,21 @@ +header("Hey", "World"); +try { + var_dump($test->post("https://ping.intera.dev", ["aaaaaaaa" => "#######################"])->query("Hey", "World")->send()->json()); + assert(false, "ERR"); +} catch (\de\interaapps\ulole\httpclient\exceptions\HttpException $e) { + echo "\n {$e->getMessage()} \n"; +} \ No newline at end of file diff --git a/uppm.json b/uppm.json new file mode 100644 index 0000000..4c9f5cd --- /dev/null +++ b/uppm.json @@ -0,0 +1,18 @@ +{ + "name": "interaapps\/ulole-http-client", + "version": "1.0.0", + "phpVersion": "8.0", + "repositories": [], + "run": { + "test": "src\/test\/testbootstrap.php" + }, + "build": {}, + "serve": {}, + "modules": { + "interaapps\/jsonplus": "1.0.6" + }, + "namespaceBindings": { + "de\\interaapps\\ulole\\httpclient": "src\/main\/de\/interaapps\/ulole\/module" + }, + "initScripts": [] +} \ No newline at end of file diff --git a/uppm.locks.json b/uppm.locks.json new file mode 100644 index 0000000..74bcbf1 --- /dev/null +++ b/uppm.locks.json @@ -0,0 +1,12 @@ +{ + "namespaceBindings": { + "de\\interaapps\\ulole\\module": ".\/src\/main\/de\/interaapps\/ulole\/module", + "de\\interaapps\\jsonplus": "modules\/interaapps-jsonplus\/src\/main\/de\/interaapps\/jsonplus" + }, + "directNamespaceBindings": {}, + "modules": { + "module": "1.0", + "interaapps\/jsonplus": "1.0.6" + }, + "initScripts": [] +} \ No newline at end of file