diff --git a/4dev/tests/UrlRequests/CoreLibsUrlRequestsCurlTest.php b/4dev/tests/UrlRequests/CoreLibsUrlRequestsCurlTest.php
new file mode 100644
index 00000000..7c39d699
--- /dev/null
+++ b/4dev/tests/UrlRequests/CoreLibsUrlRequestsCurlTest.php
@@ -0,0 +1,31 @@
+markTestIncomplete(
+ 'UrlRequests\Curl Tests have not yet been implemented'
+ );
+ }
+}
+
+// __END__
diff --git a/www/admin/class_test.url-requests.php b/www/admin/class_test.url-requests.php
new file mode 100644
index 00000000..94d64614
--- /dev/null
+++ b/www/admin/class_test.url-requests.php
@@ -0,0 +1,44 @@
+ BASE . LOG,
+ 'log_file_id' => $LOG_FILE_ID,
+ 'log_per_date' => true,
+]);
+
+$client = new Curl();
+
+$PAGE_NAME = 'TEST CLASS: URL REQUESTS CURL';
+print "";
+print "
" . $PAGE_NAME . "";
+print "";
+print '';
+print '' . $PAGE_NAME . '
';
+
+$url = 'https://soba.egplusww.jp';
+
+$data = $client->requestGet($url, []);
+
+print "";
+
+// __END__
diff --git a/www/lib/CoreLibs/UrlRequests/Curl.php b/www/lib/CoreLibs/UrlRequests/Curl.php
new file mode 100644
index 00000000..73e013ab
--- /dev/null
+++ b/www/lib/CoreLibs/UrlRequests/Curl.php
@@ -0,0 +1,405 @@
+ all the valid request type */
+ private const VALID_REQUEST_TYPES = ["get", "post", "put", "delete"];
+ /** @var int error bad request */
+ public const HTTP_BAD_REQUEST = 400;
+ /** @var int error not authorized Request */
+ public const HTTP_NOT_AUTHORIZED = 401;
+ /** @var int error forbidden */
+ public const HTTP_FORBIDDEN = 403;
+ /** @var int error not found */
+ public const HTTP_NOT_FOUND = 404;
+ /** @var int error conflict */
+ public const HTTP_CONFLICT = 409;
+ /** @var int error unprocessable entity */
+ public const HTTP_UNPROCESSABLE_ENTITY = 422;
+ /** @var int http ok request */
+ public const HTTP_OK = 200;
+ /** @var int http ok creted response */
+ public const HTTP_CREATED = 201;
+ /** @var int http ok no content */
+ public const HTTP_NO_CONTENT = 204;
+
+ /** @var string auth ident as "email:api_token */
+ private string $auth_ident;
+ /** @var bool if flagged to true, will raise an exception on failed authentication */
+ private bool $exception_on_not_authorized = false;
+
+ /**
+ * init class with auth ident token
+ *
+ * @param ?string $auth_ident [defaul=null] String to send for authentication, optional
+ * @param bool $exception_on_not_authorized [default=false] If set to true
+ * will raise excepion on http auth error
+ */
+ public function __construct(?string $auth_ident = null, bool $exception_on_not_authorized = false)
+ {
+ if (is_string($auth_ident)) {
+ $this->auth_ident = $auth_ident;
+ }
+ $this->exception_on_not_authorized = $exception_on_not_authorized;
+ }
+
+ // *********************************************************************
+ // MARK: PRIVATE METHODS
+ // *********************************************************************
+
+ // MARK: query and params convert
+
+ /**
+ * Convert Query params and combine with url
+ *
+ * @param string $url
+ * @param null|string|array $query
+ * @return string
+ */
+ private function convertQuery(string $url, null|string|array $query = null): string
+ {
+ // conert to URL encoded query if array
+ if (is_array($query)) {
+ $query = http_build_query($query);
+ }
+ // add the params to the url
+ if (!empty($query)) {
+ // add ? if the string doesn't strt with one
+ // check if URL has "?", if yes, add as "&" block
+ $param_prefix = '?';
+ if (strstr($url, '?') !== false) {
+ $param_prefix = '&';
+ }
+ // if set, strip first character
+ if (str_starts_with($query, '?') || str_starts_with($query, '&')) {
+ $query = substr($query, 1);
+ }
+ // build url string
+ $url .= $param_prefix . $query;
+ }
+ return $url;
+ }
+
+ /**
+ * Convert array params to json type string
+ *
+ * @param string|array $params
+ * @return string
+ */
+ private function convertParams(string|array $params): string
+ {
+ // convert to string as JSON block if it is an array
+ if (is_array($params)) {
+ $params = Json::jsonConvertArrayTo($params);
+ }
+ return $params;
+ }
+
+ // MARK: main curl request
+
+ /**
+ * Overall reequest call
+ *
+ * @param string $type get, post, put, delete: if not set or invalid throw error
+ * @param string $url The URL being requested,
+ * including domain and protocol
+ * @param array $headers [default=[]] Headers to be used in the request
+ * @param string|null $params [default=null] Optional url parameters for post/put requests
+ * @return array{code:string,content:string}
+ */
+ private function curlRequest(string $type, string $url, array $headers = [], ?string $params = null): array
+ {
+ if (!in_array($type, self::VALID_REQUEST_TYPES)) {
+ throw new RuntimeException(
+ json_encode([
+ 'status' => 'FAILURE',
+ 'code' => 'C003',
+ 'type' => 'InvalidRequestType',
+ 'message' => 'Invalid request type set: ' . $type,
+ 'context' => [
+ 'url' => $url,
+ 'type' => $type,
+ ],
+ ]) ?: '',
+ 0,
+ );
+ }
+ // init curl handle
+ $handle = $this->handleCurleInit($url);
+ // set the standard curl options
+ if ($headers !== []) {
+ $this->setCurlOptions($handle, $headers);
+ }
+ // for post we set POST option
+ if ($type == "post") {
+ curl_setopt($handle, CURLOPT_POST, true);
+ } elseif (in_array($type, ["put", "delete"])) {
+ curl_setopt($handle, CURLOPT_CUSTOMREQUEST, strtoupper($type));
+ }
+ if (in_array($type, ["post", "put"]) && !empty($params)) {
+ curl_setopt($handle, CURLOPT_POSTFIELDS, $params);
+ }
+ // run curl execute
+ $http_result = $this->handleCurlExec($handle);
+ // get response code and bail on not authorized
+ $http_response = $this->handleCurlResponse($http_result, $handle);
+ // return response and result
+ return [
+ 'code' => (string)$http_response,
+ 'content' => (string)$http_result
+ ];
+ }
+
+ // MARK: curl request helpers
+
+ /**
+ * Handel curl init and errors
+ *
+ * @param string $url
+ * @return \CurlHandle
+ */
+ private function handleCurleInit(string $url): \CurlHandle
+ {
+ $handle = curl_init($url);
+ if ($handle !== false) {
+ return $handle;
+ }
+ // throw Error here with all codes
+ throw new RuntimeException(
+ json_encode([
+ 'status' => 'FAILURE',
+ 'code' => 'C001',
+ 'type' => 'CurlInitError',
+ 'message' => 'Failed to init curl with url: ' . $url,
+ 'context' => [
+ 'url' => $url,
+ ],
+ ]) ?: '',
+ 0,
+ );
+ }
+
+ /**
+ * set the default curl options
+ *
+ * headers array: do not split into "key" => "value", they must be "key: value"
+ *
+ * @param \CurlHandle $handle
+ * @param array $headers list of options
+ * @return void
+ */
+ private function setCurlOptions(\CurlHandle $handle, array $headers): void
+ {
+ if (!empty($this->auth_ident)) {
+ curl_setopt($handle, CURLOPT_USERPWD, $this->auth_ident);
+ }
+ curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
+ // curl_setopt($handle, CURLOPT_FAILONERROR, true);
+ curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
+ // for debug only
+ curl_setopt($handle, CURLINFO_HEADER_OUT, true);
+ }
+
+ // MARK: Curl Exception handler
+
+ /**
+ * handles any CURL execute and on error throws a correct error message
+ *
+ * @param \CurlHandle $handle
+ * @return string
+ */
+ private function handleCurlExec(\CurlHandle $handle): string
+ {
+ // execute query
+ $http_result = curl_exec($handle);
+ if ($http_result === true) {
+ return (string)self::HTTP_OK;
+ } elseif ($http_result !== false) {
+ return $http_result;
+ }
+ $url = curl_getinfo($handle, CURLINFO_EFFECTIVE_URL);
+ $errno = curl_errno($handle);
+ $message = curl_error($handle);
+ switch ($errno) {
+ case CURLE_COULDNT_CONNECT:
+ case CURLE_COULDNT_RESOLVE_HOST:
+ case CURLE_OPERATION_TIMEOUTED:
+ $message = 'Could not connect to server (' . $url . '). Please check your '
+ . 'internet connection and try again. [' . $message . ']';
+ break;
+ case CURLE_SSL_PEER_CERTIFICATE:
+ $message = 'Could not verify SSL certificate. Please make sure '
+ . 'that your network is not intercepting certificates. '
+ . '(Try going to ' . $url . 'in your browser.) '
+ . '[' . $message . ']';
+ break;
+ case 0:
+ default:
+ $message = 'Unexpected error communicating with server: ' . $message;
+ }
+
+ // throw an error like in the normal reqeust, but set to CURL error
+ throw new RuntimeException(
+ json_encode([
+ 'status' => 'FAILURE',
+ 'code' => 'C002',
+ 'type' => 'CurlError',
+ 'message' => $message,
+ 'context' => [
+ 'url' => $url,
+ 'errno' => $errno,
+ 'message' => $message,
+ ],
+ ]) ?: '',
+ $errno
+ );
+ }
+
+ // MARK: curl response hanlder
+
+ /**
+ * Handle curl response and not auth 401 errors
+ *
+ * @param string $http_result
+ * @param \CurlHandle $handle
+ * @return string
+ */
+ private function handleCurlResponse(
+ string $http_result,
+ \CurlHandle $handle
+ ): string {
+ $http_response = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
+ if (
+ !$this->exception_on_not_authorized ||
+ $http_response !== self::HTTP_NOT_AUTHORIZED
+ ) {
+ return (string)$http_response;
+ }
+ $err = curl_errno($handle);
+ // extract all the error codes
+ $result_ar = json_decode((string)$http_result, true);
+
+ $url = curl_getinfo($handle, CURLINFO_EFFECTIVE_URL);
+ $error_status = 'ERROR';
+ $error_code = $http_response;
+ $error_type = 'UnauthorizedRequest';
+ $message = 'Request could not be finished successfully because of an authorization error';
+
+ // throw Error here with all codes
+ throw new RuntimeException(
+ json_encode([
+ 'status' => $error_status,
+ 'code' => $error_code,
+ 'type' => $error_type,
+ 'message' => $message,
+ 'context' => [
+ 'url' => $url,
+ 'result' => $result_ar,
+ ],
+ ]) ?: '',
+ $err
+ );
+ }
+
+ // *********************************************************************
+ // MARK: PUBLIC METHODS
+ // *********************************************************************
+
+ // MARK: request methods
+
+ /**
+ * Makes an request to the target url via curl: GET
+ * Returns result as string (json)
+ *
+ * @param string $url The URL being requested,
+ * including domain and protocol
+ * @param array $headers [default=[]] Headers to be used in the request
+ * @param null|string|array $query [default=null] String to pass on as GET,
+ * if array will be converted
+ * @return array{code:string,content:string} Result code and content as array, content is json
+ */
+ public function requestGet(string $url, array $headers = [], null|string|array $query = null): array
+ {
+ return $this->curlRequest("get", $this->convertQuery($url, $query), $headers);
+ }
+
+ /**
+ * Makes an request to the target url via curl: POST
+ * Returns result as string (json)
+ *
+ * @param string $url The URL being requested,
+ * including domain and protocol
+ * @param string|array $params String to pass on as POST
+ * @param array $headers Headers to be used in the request
+ * @param null|string|array $query Optinal query parameters, array will be converted
+ * @return array{code:string,content:string} Result code and content as array, content is json
+ */
+ public function requestPost(
+ string $url,
+ string|array $params,
+ array $headers,
+ null|string|array $query = null
+ ): array {
+ return $this->curlRequest(
+ "post",
+ $this->convertQuery($url, $query),
+ $headers,
+ $this->convertParams($params)
+ );
+ }
+
+ /**
+ * Makes an request to the target url via curl: PUT
+ * Returns result as string (json)
+ *
+ * @param string $url The URL being requested,
+ * including domain and protocol
+ * @param string|array $params String to pass on as POST
+ * @param array $headers Headers to be used in the request
+ * @param null|string|array $query Optinal query parameters, array will be converted
+ * @return array{code:string,content:string} Result code and content as array, content is json
+ */
+ public function requestPut(
+ string $url,
+ string|array $params,
+ array $headers,
+ null|string|array $query = null
+ ): array {
+ return $this->curlRequest(
+ "put",
+ $this->convertQuery($url, $query),
+ $headers,
+ $this->convertParams($params)
+ );
+ }
+
+ /**
+ * Makes an request to the target url via curl: DELETE
+ * Returns result as string (json)
+ *
+ * @param string $url The URL being requested,
+ * including domain and protocol
+ * @param array $headers [default=[]] Headers to be used in the request
+ * @param null|string|array $query [default=null] String to pass on as GET,
+ * if array will be converted
+ * @return array{code:string,content:string} Result code and content as array, content is json
+ */
+ public function requestDelete(string $url, array $headers = [], null|string|array $query = null): array
+ {
+ return $this->curlRequest("delete", $this->convertQuery($url, $query), $headers);
+ }
+}
+
+// __END__
diff --git a/www/lib/CoreLibs/UrlRequests/Interface/RequestsInterface.php b/www/lib/CoreLibs/UrlRequests/Interface/RequestsInterface.php
new file mode 100644
index 00000000..7e06120c
--- /dev/null
+++ b/www/lib/CoreLibs/UrlRequests/Interface/RequestsInterface.php
@@ -0,0 +1,75 @@
+ $headers Headers to be used in the request
+ * @param null|string|array $query String to pass on as GET, if array will be converted
+ * @return array{code:string,content:string} Result code and content as array, content is json
+ */
+ public function requestGet(string $url, array $headers, null|string|array $query = null): array;
+
+ /**
+ * Makes an request to the target url via curl: POST
+ * Returns result as string (json)
+ *
+ * @param string $url The URL being requested,
+ * including domain and protocol
+ * @param string|array $params String to pass on as POST
+ * @param array $headers Headers to be used in the request
+ * @param null|string|array $query URL query parameters
+ * @return array{code:string,content:string} Result code and content as array, content is json
+ */
+ public function requestPost(
+ string $url,
+ string|array $params,
+ array $headers,
+ null|string|array $query = null
+ ): array;
+
+ /**
+ * Makes an request to the target url via curl: PUT
+ * Returns result as string (json)
+ *
+ * @param string $url The URL being requested,
+ * including domain and protocol
+ * @param string|array $params String to pass on as POST
+ * @param array $headers Headers to be used in the request
+ * @param null|string|array $query String to pass on as GET, if array will be converted
+ * @return array{code:string,content:string} Result code and content as array, content is json
+ */
+ public function requestPut(
+ string $url,
+ string|array $params,
+ array $headers,
+ null|string|array $query = null
+ ): array;
+
+ /**
+ * Makes an request to the target url via curl: DELETE
+ * Returns result as string (json)
+ *
+ * @param string $url The URL being requested,
+ * including domain and protocol
+ * @param array $headers Headers to be used in the request
+ * @param null|string|array $query String to pass on as GET, if array will be converted
+ * @return array{code:string,content:string} Result code and content as array, content is json
+ */
+ public function requestDelete(string $url, array $headers, null|string|array $query = null): array;
+}
+
+// __END__