Compare commits
5 Commits
1653e6b684
...
v9.18.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8613e8977b | ||
|
|
0c51a3be87 | ||
|
|
f9cf36524e | ||
|
|
bacb9881ac | ||
|
|
f0fae1f76d |
@@ -13,16 +13,26 @@ declare(strict_types=1);
|
||||
* build return json
|
||||
*
|
||||
* @param array<string,mixed> $http_headers
|
||||
* @param string $body
|
||||
* @param ?string $body
|
||||
* @return string
|
||||
*/
|
||||
function buildContent(array $http_headers, string $body): string
|
||||
function buildContent(array $http_headers, ?string $body): string
|
||||
{
|
||||
if (is_string($body) && !empty($body)) {
|
||||
$_body = json_decode($body, true);
|
||||
if (!is_array($_body)) {
|
||||
$body = [$body];
|
||||
} else {
|
||||
$body = $_body;
|
||||
}
|
||||
} elseif (is_string($body)) {
|
||||
$body = [];
|
||||
}
|
||||
return json_encode([
|
||||
'HEADERS' => $http_headers,
|
||||
"REQUEST_TYPE" => $_SERVER['REQUEST_METHOD'],
|
||||
"PARAMS" => $_GET,
|
||||
"BODY" => json_decode($body, true)
|
||||
"BODY" => $body,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -41,11 +51,15 @@ if (!empty($http_headers['HTTP_AUTHORIZATION']) && !empty($http_headers['HTTP_RU
|
||||
exit;
|
||||
}
|
||||
|
||||
if (($file_get = file_get_contents('php://input')) === false) {
|
||||
// if server request type is get set file_get to null -> no body
|
||||
if ($_SERVER['REQUEST_METHOD'] == "GET") {
|
||||
$file_get = null;
|
||||
} elseif (($file_get = file_get_contents('php://input')) === false) {
|
||||
header("HTTP/1.1 404 Not Found");
|
||||
print buildContent($http_headers, '{"code": 404, "content": {"Error": "file_get_contents failed"}}');
|
||||
exit;
|
||||
}
|
||||
|
||||
print buildContent($http_headers, $file_get);
|
||||
|
||||
// __END__
|
||||
|
||||
@@ -47,7 +47,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
. '4dev/tests/AAASetupData/requests/http_requests.php',
|
||||
// composer package
|
||||
'https://soba.egplusww.jp/developers/clemens/core_data/composer-packages/'
|
||||
. 'CoreLibs-Composer-All/test/phpunit/AAASetupData/http_requests.php',
|
||||
. 'CoreLibs-Composer-All/test/phpunit/AAASetupData/requests/http_requests.php',
|
||||
// if we run php -S localhost:30999 -t [see below]
|
||||
// dev: /storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/4dev/tests/AAASetupData/requests/
|
||||
// composer: /storage/var/www/html/developers/clemens/core_data/composer-packages/CoreLibs-Composer-All/test/phpunit/AAASetupData
|
||||
@@ -732,7 +732,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
// MARK: test basi call provider
|
||||
// MARK: test basic call provider
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
@@ -768,7 +768,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
'type' => $type,
|
||||
'options' => null,
|
||||
'return_code' => "200",
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":[],"BODY":null}'
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":[],"BODY":[]}'
|
||||
];
|
||||
$provider["basic " . $type . ", query options"] = [
|
||||
'type' => $type,
|
||||
@@ -776,7 +776,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
"query" => ["foo" => "bar"],
|
||||
],
|
||||
'return_code' => "200",
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":{"foo":"bar"},"BODY":null}'
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":{"foo":"bar"},"BODY":[]}'
|
||||
];
|
||||
$provider["basic " . $type . ", query/body options"] = [
|
||||
'type' => $type,
|
||||
@@ -787,6 +787,22 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
'return_code' => "200",
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":{"foo":"bar"},"BODY":{"foobar":"barbaz"}}'
|
||||
];
|
||||
$provider["basic " . $type . ", body options"] = [
|
||||
'type' => $type,
|
||||
'options' => [
|
||||
"body" => ["foobar" => "barbaz"],
|
||||
],
|
||||
'return_code' => "200",
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":[],"BODY":{"foobar":"barbaz"}}'
|
||||
];
|
||||
$provider["basic " . $type . ", body options as string"] = [
|
||||
'type' => $type,
|
||||
'options' => [
|
||||
"body" => "body is a string",
|
||||
],
|
||||
'return_code' => "200",
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":[],"BODY":["body is a string"]}'
|
||||
];
|
||||
}
|
||||
// MARK: post/put/patch
|
||||
foreach (['post', 'put', 'patch'] as $type) {
|
||||
@@ -814,7 +830,24 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
'return_code' => "200",
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":{"foo":"bar"},"BODY":{"foobar":"barbaz"}}'
|
||||
];
|
||||
$provider["basic " . $type . ", body options"] = [
|
||||
'type' => $type,
|
||||
'options' => [
|
||||
"body" => ["foobar" => "barbaz"],
|
||||
],
|
||||
'return_code' => "200",
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":[],"BODY":{"foobar":"barbaz"}}'
|
||||
];
|
||||
$provider["basic " . $type . ", body option as string"] = [
|
||||
'type' => $type,
|
||||
'options' => [
|
||||
"body" => "body is a string",
|
||||
],
|
||||
'return_code' => "200",
|
||||
'return_content' => '{"HEADERS":{"HTTP_USER_AGENT":"CoreLibsUrlRequestCurl\/1","HTTP_ACCEPT":"*\/*","HTTP_HOST":"soba.egplusww.jp"},"REQUEST_TYPE":"' . strtoupper($type) . '","PARAMS":[],"BODY":["body is a string"]}'
|
||||
];
|
||||
}
|
||||
// $provider['"basic post']
|
||||
return $provider;
|
||||
// phpcs:enable Generic.Files.LineLength
|
||||
}
|
||||
@@ -917,7 +950,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: multi requests with same base connection
|
||||
// MARK: multi requests with same base connection
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
@@ -970,17 +1003,67 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
. '"HTTP_THIRD_CALL":"delete","HTTP_ACCEPT":"*\/*",'
|
||||
. '"HTTP_HOST":"soba.egplusww.jp"},'
|
||||
. '"REQUEST_TYPE":"DELETE",'
|
||||
. '"PARAMS":[],"BODY":null}',
|
||||
. '"PARAMS":[],"BODY":[]}',
|
||||
$response['content'],
|
||||
'multi call: delete content not matching'
|
||||
);
|
||||
}
|
||||
|
||||
// MARK: auth header set via config
|
||||
|
||||
/**
|
||||
* Test auth settings and auth override
|
||||
*
|
||||
* @testdox UrlRequests\Curl auth test call
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUrlRequestsCurlAuthHeader()
|
||||
{
|
||||
$curl = new \CoreLibs\UrlRequests\Curl([
|
||||
"auth" => ["user", "pass", "basic"],
|
||||
"http_errors" => false,
|
||||
]);
|
||||
$curl->request('get', $this->url_basic);
|
||||
// check that the auth header matches
|
||||
$this->assertContains(
|
||||
"Authorization:Basic dXNlcjpwYXNz",
|
||||
$curl->getHeadersSent()
|
||||
);
|
||||
// if we sent new request with auth header, this one should not be used
|
||||
$curl->request('get', $this->url_basic, [
|
||||
"headers" => ["Authorization" => "Failed"]
|
||||
]);
|
||||
// check that the auth header matches
|
||||
$this->assertContains(
|
||||
"Authorization:Basic dXNlcjpwYXNz",
|
||||
$curl->getHeadersSent()
|
||||
);
|
||||
// override auth: reset
|
||||
$curl->request('get', $this->url_basic, [
|
||||
"auth" => null
|
||||
]);
|
||||
$this->assertNotContains(
|
||||
"Authorization:Basic dXNlcjpwYXNz",
|
||||
$curl->getHeadersSent()
|
||||
);
|
||||
// override auth: different auth
|
||||
$curl->request('get', $this->url_basic, [
|
||||
"auth" => ["user2", "pass2", "basic"]
|
||||
]);
|
||||
// check that the auth header matches
|
||||
$this->assertContains(
|
||||
"Authorization:Basic dXNlcjI6cGFzczI=",
|
||||
$curl->getHeadersSent()
|
||||
);
|
||||
}
|
||||
|
||||
// MARK: test exceptions
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* Exception:InvalidRequestType
|
||||
*
|
||||
* @covers ::request
|
||||
* @testdox UrlRequests\Curl Exception:InvalidRequestType
|
||||
*
|
||||
* @return void
|
||||
@@ -993,6 +1076,46 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
$curl->request('wrong', 'http://foo.bar.com');
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception:InvalidHeaderKey
|
||||
*
|
||||
* @covers ::request
|
||||
* @testdox UrlRequests\Curl Exception:InvalidHeaderKey
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExceptionInvalidHeaderKey(): void
|
||||
{
|
||||
$curl = new \CoreLibs\UrlRequests\Curl();
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessageMatches("/InvalidHeaderKey/");
|
||||
$curl->request('get', $this->url_basic, [
|
||||
"headers" => [
|
||||
"(invalid-key)" => "key"
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception:InvalidHeaderValue
|
||||
*
|
||||
* @covers ::request
|
||||
* @testdox UrlRequests\Curl Exception:InvalidHeaderValue
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExceptionInvalidHeaderValue(): void
|
||||
{
|
||||
$curl = new \CoreLibs\UrlRequests\Curl();
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessageMatches("/InvalidHeaderValue/");
|
||||
$curl->request('get', $this->url_basic, [
|
||||
"headers" => [
|
||||
"invalid-value" => "\x19\x10"
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Exception:CurlInitError
|
||||
*
|
||||
@@ -1006,9 +1129,10 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
// }
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* Exception:CurlExecError
|
||||
*
|
||||
* @testdox UrlRequests\Curl Exception:CurlError
|
||||
* @covers ::request
|
||||
* @testdox UrlRequests\Curl Exception:CurlExecError
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -1024,6 +1148,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
/**
|
||||
* Exception:ClientError
|
||||
*
|
||||
* @covers ::request
|
||||
* @testdox UrlRequests\Curl Exception:ClientError
|
||||
*
|
||||
* @return void
|
||||
@@ -1033,7 +1158,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
$curl = new \CoreLibs\UrlRequests\Curl(["http_errors" => true]);
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessageMatches("/ClientError/");
|
||||
$curl->get($this->url_basic, [
|
||||
$curl->request('get', $this->url_basic, [
|
||||
"headers" => [
|
||||
"Authorization" => "schmalztiegel",
|
||||
"RunAuthTest" => "yes",
|
||||
@@ -1044,6 +1169,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
/**
|
||||
* Exception:ClientError
|
||||
*
|
||||
* @covers ::request
|
||||
* @testdox UrlRequests\Curl Exception:ClientError on call enable
|
||||
*
|
||||
* @return void
|
||||
@@ -1053,7 +1179,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
$curl = new \CoreLibs\UrlRequests\Curl(["http_errors" => false]);
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessageMatches("/ClientError/");
|
||||
$curl->get($this->url_basic, [
|
||||
$curl->request('get', $this->url_basic, [
|
||||
"headers" => [
|
||||
"Authorization" => "schmalztiegel",
|
||||
"RunAuthTest" => "yes",
|
||||
@@ -1065,6 +1191,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
/**
|
||||
* Exception:ClientError
|
||||
*
|
||||
* @covers ::request
|
||||
* @testdox UrlRequests\Curl Exception:ClientError unset on call
|
||||
*
|
||||
* @return void
|
||||
@@ -1073,7 +1200,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
{
|
||||
// if true, with false it has to be off
|
||||
$curl = new \CoreLibs\UrlRequests\Curl(["http_errors" => true]);
|
||||
$response = $curl->get($this->url_basic, [
|
||||
$response = $curl->request('get', $this->url_basic, [
|
||||
"headers" => [
|
||||
"Authorization" => "schmalztiegel",
|
||||
"RunAuthTest" => "yes",
|
||||
@@ -1087,7 +1214,7 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
);
|
||||
// if false, null should not change it
|
||||
$curl = new \CoreLibs\UrlRequests\Curl(["http_errors" => false]);
|
||||
$response = $curl->get($this->url_basic, [
|
||||
$response = $curl->request('get', $this->url_basic, [
|
||||
"headers" => [
|
||||
"Authorization" => "schmalztiegel",
|
||||
"RunAuthTest" => "yes",
|
||||
@@ -1100,24 +1227,6 @@ final class CoreLibsUrlRequestsCurlTest extends TestCase
|
||||
'Unset Exception failed with null'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @testdox UrlRequests\Curl Exception:DuplicatedArrayKey
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testExceptionDuplicatedArrayKey(): void
|
||||
{
|
||||
$curl = new \CoreLibs\UrlRequests\Curl();
|
||||
$this->expectException(\UnexpectedValueException::class);
|
||||
$this->expectExceptionMessageMatches("/DuplicatedArrayKey/");
|
||||
$curl->prepareHeaders([
|
||||
'header-double:a',
|
||||
'header-double:b',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
|
||||
@@ -16,16 +16,26 @@ $log = new CoreLibs\Logging\Logging([
|
||||
* build return json
|
||||
*
|
||||
* @param array<string,mixed> $http_headers
|
||||
* @param string $body
|
||||
* @param ?string $body
|
||||
* @return string
|
||||
*/
|
||||
function buildContent(array $http_headers, string $body): string
|
||||
function buildContent(array $http_headers, ?string $body): string
|
||||
{
|
||||
if (is_string($body) && !empty($body)) {
|
||||
$_body = Json::jsonConvertToArray($body);
|
||||
if (Json::jsonGetLastError()) {
|
||||
$body = [$body];
|
||||
} else {
|
||||
$body = $_body;
|
||||
}
|
||||
} elseif (is_string($body)) {
|
||||
$body = [];
|
||||
}
|
||||
return Json::jsonConvertArrayTo([
|
||||
'HEADERS' => $http_headers,
|
||||
"REQUEST_TYPE" => $_SERVER['REQUEST_METHOD'],
|
||||
"PARAMS" => $_GET,
|
||||
"BODY" => Json::jsonConvertToArray($body),
|
||||
"BODY" => $body,
|
||||
// "STRING_BODY" => $body,
|
||||
]);
|
||||
}
|
||||
@@ -45,7 +55,10 @@ if (!empty($http_headers['HTTP_AUTHORIZATION']) && !empty($http_headers['HTTP_RU
|
||||
exit;
|
||||
}
|
||||
|
||||
if (($file_get = file_get_contents('php://input')) === false) {
|
||||
// if server request type is get set file_get to null -> no body
|
||||
if ($_SERVER['REQUEST_METHOD'] == "GET") {
|
||||
$file_get = null;
|
||||
} elseif (($file_get = file_get_contents('php://input')) === false) {
|
||||
header("HTTP/1.1 404 Not Found");
|
||||
print buildContent($http_headers, '{"code": 404, "content": {"Error": "file_get_contents failed"}}');
|
||||
exit;
|
||||
|
||||
@@ -40,11 +40,11 @@ $data = $client->get(
|
||||
'https://soba.egplusww.jp/developers/clemens/core_data/php_libraries/trunk/www/admin/UrlRequests.target.php'
|
||||
. '?other=get_a',
|
||||
[
|
||||
'headers' => $client->prepareHeaders([
|
||||
'test-header: ABC',
|
||||
'info-request-type: _GET',
|
||||
'headers' => [
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_GET',
|
||||
'Funk-pop' => 'Semlly god'
|
||||
]),
|
||||
],
|
||||
'query' => ['foo' => 'BAR']
|
||||
]
|
||||
);
|
||||
@@ -78,11 +78,11 @@ $data = $client->request(
|
||||
. 'trunk/www/admin/UrlRequests.target.php'
|
||||
. '?other=get_a',
|
||||
[
|
||||
"headers" => $client->prepareHeaders([
|
||||
'test-header: ABC',
|
||||
'info-request-type: _GET',
|
||||
"headers" => [
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_GET',
|
||||
'Funk-pop' => 'Semlly god'
|
||||
]),
|
||||
],
|
||||
"query" => ['foo' => 'BAR'],
|
||||
],
|
||||
);
|
||||
@@ -94,12 +94,12 @@ $data = $client->post(
|
||||
. '?other=post_a',
|
||||
[
|
||||
'body' => ['payload' => 'data post'],
|
||||
'headers' => $client->prepareHeaders([
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'test-header: ABC',
|
||||
'info-request-type: _POST'
|
||||
]),
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_POST',
|
||||
],
|
||||
'query' => ['foo' => 'BAR post'],
|
||||
]
|
||||
);
|
||||
@@ -111,16 +111,33 @@ $data = $client->request(
|
||||
. '?other=post_a',
|
||||
[
|
||||
"body" => ['payload' => 'data post', 'request' => 'I am the request body'],
|
||||
"headers" => $client->prepareHeaders([
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'test-header: ABC',
|
||||
'info-request-type: _POST'
|
||||
]),
|
||||
"headers" => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_POST',
|
||||
],
|
||||
"query" => ['foo' => 'BAR post'],
|
||||
]
|
||||
);
|
||||
print "[request] _POST RESPONSE: <pre>" . print_r($data, true) . "</pre>";
|
||||
print "<hr>";
|
||||
$data = $client->request(
|
||||
"post",
|
||||
'https://soba.egplusww.jp/developers/clemens/core_data/php_libraries/trunk/www/admin/UrlRequests.target.php'
|
||||
. '?other=post_a',
|
||||
[
|
||||
"body" => 'string body here',
|
||||
"headers" => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_POST',
|
||||
],
|
||||
"query" => ['foo' => 'BAR post'],
|
||||
]
|
||||
);
|
||||
print "[request|string body] _POST RESPONSE: <pre>" . print_r($data, true) . "</pre>";
|
||||
|
||||
print "<hr>";
|
||||
$data = $client->put(
|
||||
@@ -128,12 +145,12 @@ $data = $client->put(
|
||||
. '?other=put_a',
|
||||
[
|
||||
"body" => ['payload' => 'data put'],
|
||||
"headers" => $client->prepareHeaders([
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'test-header: ABC',
|
||||
'info-request-type: _PUT'
|
||||
]),
|
||||
"headers" => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_PUT',
|
||||
],
|
||||
'query' => ['foo' => 'BAR put'],
|
||||
]
|
||||
);
|
||||
@@ -145,12 +162,12 @@ $data = $client->patch(
|
||||
. '?other=patch_a',
|
||||
[
|
||||
"body" => ['payload' => 'data patch'],
|
||||
"headers" => $client->prepareHeaders([
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'test-header: ABC',
|
||||
'info-request-type: _PATCH'
|
||||
]),
|
||||
"headers" => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_PATCH',
|
||||
],
|
||||
'query' => ['foo' => 'BAR patch'],
|
||||
]
|
||||
);
|
||||
@@ -162,12 +179,12 @@ $data = $client->delete(
|
||||
. '?other=delete_no_body_a',
|
||||
[
|
||||
"body" => null,
|
||||
"headers" => $client->prepareHeaders([
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'test-header: ABC',
|
||||
'info-request-type: _DELETE'
|
||||
]),
|
||||
"headers" => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_DELETE',
|
||||
],
|
||||
"query" => ['foo' => 'BAR delete'],
|
||||
]
|
||||
);
|
||||
@@ -179,12 +196,12 @@ $data = $client->delete(
|
||||
. '?other=delete_body_a',
|
||||
[
|
||||
"body" => ['payload' => 'data delete'],
|
||||
"headers" => $client->prepareHeaders([
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'test-header: ABC',
|
||||
'info-request-type: _DELETE'
|
||||
]),
|
||||
"headers" => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
'test-header' => 'ABC',
|
||||
'info-request-type' => '_DELETE',
|
||||
],
|
||||
"query" => ['foo' => 'BAR delete'],
|
||||
]
|
||||
);
|
||||
@@ -294,6 +311,24 @@ try {
|
||||
} catch (Exception $e) {
|
||||
print "Exception: <pre>" . print_r(json_decode($e->getMessage(), true), true) . "</pre><br>";
|
||||
}
|
||||
print "AUTH REQUEST HEADER SET:<br>";
|
||||
try {
|
||||
$uc = new Curl([
|
||||
"base_uri" => 'https://soba.egplusww.jp/developers/clemens/core_data/php_libraries/trunk/www/admin/',
|
||||
"auth" => ["user", "pass", "basic"],
|
||||
"headers" => [
|
||||
"Authorization" => "schmalztiegel",
|
||||
"RunAuthTest" => "yes",
|
||||
]
|
||||
]);
|
||||
$response = $uc->get('UrlRequests.target.php');
|
||||
print "AUTH REQUEST (HEADER): <pre>" . print_r($response, true) . "</pre>";
|
||||
print "[uc] SENT URL: " . $uc->getUrlSent() . "<br>";
|
||||
print "[uc] SENT URL PARSED: <pre>" . print_r($uc->getUrlParsedSent(), true) . "</pre>";
|
||||
print "[uc] SENT HEADERS: <pre>" . print_r($uc->getHeadersSent(), true) . "</pre>";
|
||||
} catch (Exception $e) {
|
||||
print "Exception: <pre>" . print_r(json_decode($e->getMessage(), true), true) . "</pre><br>";
|
||||
}
|
||||
|
||||
print "<hr>";
|
||||
$uc = new Curl([
|
||||
@@ -308,6 +343,19 @@ print "[uc] SENT URL: " . $uc->getUrlSent() . "<br>";
|
||||
print "[uc] SENT URL PARSED: <pre>" . print_r($uc->getUrlParsedSent(), true) . "</pre>";
|
||||
print "[uc] SENT HEADERS: <pre>" . print_r($uc->getHeadersSent(), true) . "</pre>";
|
||||
|
||||
print "<hr>";
|
||||
$uc = new Curl([
|
||||
"base_uri" => 'https://soba.egplusww.jp/developers/clemens/core_data/php_libraries/trunk/www/admin/',
|
||||
"headers" => [
|
||||
'bar' => 'foo:bar'
|
||||
]
|
||||
]);
|
||||
$response = $uc->get('UrlRequests.target.php');
|
||||
print "HEADER SET TEST REQUEST: <pre>" . print_r($response, true) . "</pre>";
|
||||
print "[uc] SENT URL: " . $uc->getUrlSent() . "<br>";
|
||||
print "[uc] SENT URL PARSED: <pre>" . print_r($uc->getUrlParsedSent(), true) . "</pre>";
|
||||
print "[uc] SENT HEADERS: <pre>" . print_r($uc->getHeadersSent(), true) . "</pre>";
|
||||
|
||||
print "</body></html>";
|
||||
|
||||
// __END__
|
||||
|
||||
@@ -18,10 +18,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\UrlRequests;
|
||||
|
||||
use RuntimeException;
|
||||
use CoreLibs\Convert\Json;
|
||||
|
||||
/** @package CoreLibs\UrlRequests */
|
||||
class Curl implements Interface\RequestsInterface
|
||||
{
|
||||
// all general calls: get/post/put/patch/delete
|
||||
@@ -61,12 +59,11 @@ class Curl implements Interface\RequestsInterface
|
||||
/** @var array{auth?:array{0:string,1:string,2:string},http_errors:bool,base_uri:string,headers:array<string,string|array<string>>,query:array<string,string>,timeout:float,connection_timeout:float} config settings as
|
||||
*phpcs:enable Generic.Files.LineLength
|
||||
* auth: [0: user, 1: password, 2: auth type]
|
||||
* http_errors: default true, bool true/false for throwing exception on >= 400 HTTP errors
|
||||
* base_uri: base url to set, will prefix all urls given in calls
|
||||
* headers: (array) base headers, can be overwritten by headers set in call
|
||||
* timeout: default 0, in seconds (CURLOPT_TIMEOUT_MS)
|
||||
* connect_timeout: default 300, in seconds (CURLOPT_CONNECTTIMEOUT_MS)
|
||||
* : below is not a guzzleHttp config
|
||||
* http_errors: default true, bool true/false for throwing exception on >= 400 HTTP errors
|
||||
*/
|
||||
private array $config = [
|
||||
'http_errors' => true,
|
||||
@@ -131,29 +128,10 @@ class Curl implements Interface\RequestsInterface
|
||||
];
|
||||
// auth string is array of 0: user, 1: password, 2: auth type
|
||||
if (!empty($config['auth']) && is_array($config['auth'])) {
|
||||
// base auth sets the header actually
|
||||
$type = isset($config['auth'][2]) ? strtolower($config['auth'][2]) : 'basic';
|
||||
$userpwd = $config['auth'][0] . ':' . $config['auth'][1];
|
||||
switch ($type) {
|
||||
case 'basic':
|
||||
$this->auth_basic_header = 'Basic ' . base64_encode(
|
||||
$userpwd
|
||||
);
|
||||
// if (!isset($config['headers']['Authorization'])) {
|
||||
// $config['headers']['Authorization'] = 'Basic ' . base64_encode(
|
||||
// $userpwd
|
||||
// );
|
||||
// }
|
||||
break;
|
||||
case 'digest':
|
||||
$this->auth_type = CURLAUTH_DIGEST;
|
||||
$this->auth_userpwd = $userpwd;
|
||||
break;
|
||||
case 'ntlm':
|
||||
$this->auth_type = CURLAUTH_NTLM;
|
||||
$this->auth_userpwd = $userpwd;
|
||||
break;
|
||||
}
|
||||
$auth_data = $this->authParser($config['auth']);
|
||||
$this->auth_basic_header = $auth_data['auth_basic_header'];
|
||||
$this->auth_type = $auth_data['auth_type'];
|
||||
$this->auth_userpwd = $auth_data['auth_userpwd'];
|
||||
}
|
||||
// only set if bool
|
||||
if (
|
||||
@@ -189,6 +167,46 @@ class Curl implements Interface\RequestsInterface
|
||||
$this->config = array_merge($default_config, $config);
|
||||
}
|
||||
|
||||
// MARK: auth parser
|
||||
|
||||
/**
|
||||
* set various auth parameters and return them as array for further processing
|
||||
*
|
||||
* @param array{0:string,1:string,2:string} $auth
|
||||
* @return array{auth_basic_header:string,auth_type:int,auth_userpwd:string}
|
||||
*/
|
||||
private function authParser(array $auth): array
|
||||
{
|
||||
$return_auth = [
|
||||
'auth_basic_header' => '',
|
||||
'auth_type' => 0,
|
||||
'auth_userpwd' => '',
|
||||
];
|
||||
// on empty return as is, to force defaults
|
||||
if ($auth === []) {
|
||||
return $return_auth;
|
||||
}
|
||||
// base auth sets the header actually
|
||||
$type = isset($auth[2]) ? strtolower($auth[2]) : 'basic';
|
||||
$userpwd = $auth[0] . ':' . $auth[1];
|
||||
switch ($type) {
|
||||
case 'basic':
|
||||
$return_auth['auth_basic_header'] = 'Basic ' . base64_encode(
|
||||
$userpwd
|
||||
);
|
||||
break;
|
||||
case 'digest':
|
||||
$return_auth['auth_type'] = CURLAUTH_DIGEST;
|
||||
$return_auth['auth_userpwd'] = $userpwd;
|
||||
break;
|
||||
case 'ntlm':
|
||||
$return_auth['auth_type'] = CURLAUTH_NTLM;
|
||||
$return_auth['auth_userpwd'] = $userpwd;
|
||||
break;
|
||||
}
|
||||
return $return_auth;
|
||||
}
|
||||
|
||||
// MARK: parse and build url
|
||||
|
||||
/**
|
||||
@@ -358,6 +376,8 @@ class Curl implements Interface\RequestsInterface
|
||||
// convert to string as JSON block if it is an array
|
||||
if (is_array($body)) {
|
||||
$params = Json::jsonConvertArrayTo($body);
|
||||
} elseif (is_string($body)) {
|
||||
$params = $body;
|
||||
}
|
||||
return $params ?? '';
|
||||
}
|
||||
@@ -373,6 +393,7 @@ class Curl implements Interface\RequestsInterface
|
||||
private function convertHeaders(array $headers): array
|
||||
{
|
||||
$return_headers = [];
|
||||
$header_keys = [];
|
||||
foreach ($headers as $key => $value) {
|
||||
if (!is_string($key)) {
|
||||
// TODO: throw error
|
||||
@@ -380,8 +401,19 @@ class Curl implements Interface\RequestsInterface
|
||||
}
|
||||
// bad if not valid header key
|
||||
if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $key)) {
|
||||
// TODO throw error
|
||||
continue;
|
||||
throw new \UnexpectedValueException(
|
||||
Json::jsonConvertArrayTo([
|
||||
'status' => 'ERROR',
|
||||
'code' => 'R002',
|
||||
'type' => 'InvalidHeaderKey',
|
||||
'message' => 'Header key contains invalid characters',
|
||||
'context' => [
|
||||
'key' => $key,
|
||||
'allowed' => '/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D',
|
||||
],
|
||||
]),
|
||||
1
|
||||
);
|
||||
}
|
||||
// if value is array, join to string
|
||||
if (is_array($value)) {
|
||||
@@ -390,8 +422,20 @@ class Curl implements Interface\RequestsInterface
|
||||
$value = trim((string)$value, " \t");
|
||||
// header values must be valid
|
||||
if (!preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D', $value)) {
|
||||
// TODO throw error
|
||||
continue;
|
||||
throw new \UnexpectedValueException(
|
||||
Json::jsonConvertArrayTo([
|
||||
'status' => 'ERROR',
|
||||
'code' => 'R003',
|
||||
'type' => 'InvalidHeaderValue',
|
||||
'message' => 'Header value contains invalid characters',
|
||||
'context' => [
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
'allowed' => '/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D',
|
||||
],
|
||||
]),
|
||||
1
|
||||
);
|
||||
}
|
||||
$return_headers[] = (string)$key . ':' . $value;
|
||||
}
|
||||
@@ -404,14 +448,23 @@ class Curl implements Interface\RequestsInterface
|
||||
* Authorization
|
||||
* User-Agent
|
||||
*
|
||||
* @return array<string,string>
|
||||
* @param array<string,string|array<string>> $headers already set headers
|
||||
* @param ?string $auth_basic_header
|
||||
* @return array<string,string|array<string>>
|
||||
*/
|
||||
private function buildDefaultHeaders(): array
|
||||
private function buildDefaultHeaders(array $headers = [], ?string $auth_basic_header = ''): array
|
||||
{
|
||||
$headers = [];
|
||||
// add auth header if set
|
||||
if (!empty($this->auth_basic_header)) {
|
||||
$headers['Authorization'] = $this->auth_basic_header;
|
||||
// add auth header if set, will overwrite any already set auth header
|
||||
if ($auth_basic_header !== null && $auth_basic_header == '' && !empty($this->auth_basic_header)) {
|
||||
$auth_basic_header = $this->auth_basic_header;
|
||||
}
|
||||
if (!empty($auth_basic_header)) {
|
||||
// check if there is any auth header set, remove that one
|
||||
if (!empty($auth_header_set = $this->headers_named[strtolower('Authorization')] ?? null)) {
|
||||
unset($headers[$auth_header_set]);
|
||||
}
|
||||
// set new auth header
|
||||
$headers['Authorization'] = $auth_basic_header;
|
||||
}
|
||||
// always add HTTP_HOST and HTTP_USER_AGENT
|
||||
if (!isset($headers[strtolower('User-Agent')])) {
|
||||
@@ -424,14 +477,15 @@ class Curl implements Interface\RequestsInterface
|
||||
* Build headers, combine with global headers of they are set
|
||||
*
|
||||
* @param null|array<string,string|array<string>> $headers
|
||||
* @param ?string $auth_basic_header
|
||||
* @return array<string,string|array<string>>
|
||||
*/
|
||||
private function buildHeaders(null|array $headers): array
|
||||
private function buildHeaders(null|array $headers, ?string $auth_basic_header): array
|
||||
{
|
||||
// if headers is null, return empty headers, do not set config default headers
|
||||
// but the automatic set User-Agent and Authorization headers are always set
|
||||
if ($headers === null) {
|
||||
return $this->buildDefaultHeaders();
|
||||
return $this->buildDefaultHeaders(auth_basic_header: $auth_basic_header);
|
||||
}
|
||||
// merge master headers with sub headers, sub headers overwrite master headers
|
||||
if (!empty($this->config['headers'])) {
|
||||
@@ -449,42 +503,81 @@ class Curl implements Interface\RequestsInterface
|
||||
$headers[$key] = $this->config['headers'][$key];
|
||||
}
|
||||
}
|
||||
$headers = array_merge($headers, $this->buildDefaultHeaders());
|
||||
$headers = $this->buildDefaultHeaders($headers, $auth_basic_header);
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the array block that is sent to the request call
|
||||
* Make sure that if headers is set as key but null it stays null and set to empty array
|
||||
* if headers key is missing
|
||||
* "get" calls do not set any body (null)
|
||||
*
|
||||
* phpcs:disable Generic.Files.LineLength
|
||||
* @param string $type if set as get do not add body, else add body
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Request options
|
||||
* @return array{auth:null|array{0:string,1:string,2:string},headers:null|array<string,string|array<string>>,query:null|array<string,string>,body:null|string|array<mixed>,http_errors:null|bool}
|
||||
* phpcs:enable Generic.Files.LineLength
|
||||
*/
|
||||
private function setOptions(string $type, array $options): array
|
||||
{
|
||||
return [
|
||||
"auth" => !array_key_exists('auth', $options) ? ['', '', ''] : $options['auth'],
|
||||
"headers" => !array_key_exists('headers', $options) ? [] : $options['headers'],
|
||||
"query" => $options['query'] ?? null,
|
||||
"http_errors" => !array_key_exists('http_errors', $options) ? null : $options['http_errors'],
|
||||
"body" => $options["body"] ??
|
||||
// check if we need a payload data set, set empty on not set
|
||||
(in_array($type, self::MANDATORY_POST_FIELDS) && !isset($options['body']) ? [] : null)
|
||||
];
|
||||
}
|
||||
|
||||
// MARK: main curl request
|
||||
|
||||
/**
|
||||
* Overall request call
|
||||
*
|
||||
* @param string $type get, post, pathc, put, delete:
|
||||
* if not set or invalid throw error
|
||||
* @param string $url The URL being requested,
|
||||
* including domain and protocol
|
||||
* @param null|array<string,string|array<string>> $headers Headers to be used in the request
|
||||
* @param null|array<string,string> $query Optinal query parameters
|
||||
* @param null|string|array<string,mixed> $body Data body, converted to JSON
|
||||
* @param null|bool $http_errors Throw exception on http response
|
||||
* 400 or higher if set to true
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string}
|
||||
* phpcs:disable Generic.Files.LineLength
|
||||
* @param string $type get, post, pathc, put, delete:
|
||||
* if not set or invalid throw error
|
||||
* @param string $url The URL being requested,
|
||||
* including domain and protocol
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Request options
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} Return content
|
||||
* code: HTTP code, if http_errors if off, this can also hold 400 or 500 type codes
|
||||
* headers: earch header entry has an array of the entries, can be more than one if proxied, etc
|
||||
* content: content string as is, if JSON type must be decoded afterwards
|
||||
* @throws \RuntimeException if type param is not valid
|
||||
* phpcs:enable Generic.Files.LineLength
|
||||
*/
|
||||
private function curlRequest(
|
||||
string $type,
|
||||
string $url,
|
||||
null|array $headers,
|
||||
null|array $query,
|
||||
null|string|array $body,
|
||||
null|bool $http_errors,
|
||||
array $options,
|
||||
): array {
|
||||
$this->url = $this->buildQuery($url, $query);
|
||||
$this->headers = $this->convertHeaders($this->buildHeaders($headers));
|
||||
// check if we need a payload data set, set empty on not set
|
||||
$options = $this->setOptions($type, $options);
|
||||
// set auth from override
|
||||
if (is_array($options['auth'])) {
|
||||
$auth_data = $this->authParser($options['auth']);
|
||||
} else {
|
||||
$auth_data = [
|
||||
'auth_basic_header' => null,
|
||||
'auth_type' => null,
|
||||
'auth_userpwd' => null,
|
||||
];
|
||||
}
|
||||
// build url
|
||||
$this->url = $this->buildQuery($url, $options['query']);
|
||||
$this->headers = $this->convertHeaders($this->buildHeaders(
|
||||
$options['headers'],
|
||||
$auth_data['auth_basic_header']
|
||||
));
|
||||
if (!in_array($type, self::VALID_REQUEST_TYPES)) {
|
||||
throw new RuntimeException(
|
||||
json_encode([
|
||||
throw new \RuntimeException(
|
||||
Json::jsonConvertArrayTo([
|
||||
'status' => 'ERROR',
|
||||
'code' => 'R002',
|
||||
'code' => 'R001',
|
||||
'type' => 'InvalidRequestType',
|
||||
'message' => 'Invalid request type set: ' . $type,
|
||||
'context' => [
|
||||
@@ -492,14 +585,17 @@ class Curl implements Interface\RequestsInterface
|
||||
'url' => $this->url,
|
||||
'headers' => $this->headers,
|
||||
],
|
||||
]) ?: '',
|
||||
]),
|
||||
0,
|
||||
);
|
||||
}
|
||||
// init curl handle
|
||||
$handle = $this->handleCurleInit($this->url);
|
||||
// set the standard curl options
|
||||
$this->setCurlOptions($handle, $this->headers);
|
||||
$this->setCurlOptions($handle, $this->headers, [
|
||||
'auth_type' => $auth_data['auth_type'],
|
||||
'auth_userpwd' => $auth_data['auth_userpwd'],
|
||||
]);
|
||||
// for post we set POST option
|
||||
if ($type == "post") {
|
||||
curl_setopt($handle, CURLOPT_POST, true);
|
||||
@@ -507,8 +603,8 @@ class Curl implements Interface\RequestsInterface
|
||||
curl_setopt($handle, CURLOPT_CUSTOMREQUEST, strtoupper($type));
|
||||
}
|
||||
// set body data if not null, will send empty [] for empty data
|
||||
if (in_array($type, self::HAVE_POST_FIELDS) && $body !== null) {
|
||||
curl_setopt($handle, CURLOPT_POSTFIELDS, $this->convertPayloadData($body));
|
||||
if (in_array($type, self::HAVE_POST_FIELDS) && $options['body'] !== null) {
|
||||
curl_setopt($handle, CURLOPT_POSTFIELDS, $this->convertPayloadData($options['body']));
|
||||
}
|
||||
// reset all headers before we start the call
|
||||
$this->received_headers = [];
|
||||
@@ -517,7 +613,7 @@ class Curl implements Interface\RequestsInterface
|
||||
// for debug
|
||||
// print "CURLINFO_HEADER_OUT: <pre>" . curl_getinfo($handle, CURLINFO_HEADER_OUT) . "</pre>";
|
||||
// get response code and bail on not authorized
|
||||
$http_response = $this->handleCurlResponse($http_result, $http_errors, $handle);
|
||||
$http_response = $this->handleCurlResponse($handle, $http_result, $options['http_errors']);
|
||||
// close handler
|
||||
$this->handleCurlClose($handle);
|
||||
// return response and result
|
||||
@@ -544,8 +640,8 @@ class Curl implements Interface\RequestsInterface
|
||||
return $handle;
|
||||
}
|
||||
// throw Error here with all codes
|
||||
throw new RuntimeException(
|
||||
json_encode([
|
||||
throw new \RuntimeException(
|
||||
Json::jsonConvertArrayTo([
|
||||
'status' => 'FAILURE',
|
||||
'code' => 'C001',
|
||||
'type' => 'CurlInitError',
|
||||
@@ -553,7 +649,7 @@ class Curl implements Interface\RequestsInterface
|
||||
'context' => [
|
||||
'url' => $url,
|
||||
],
|
||||
]) ?: '',
|
||||
]),
|
||||
0,
|
||||
);
|
||||
}
|
||||
@@ -567,14 +663,26 @@ class Curl implements Interface\RequestsInterface
|
||||
*
|
||||
* @param \CurlHandle $handle
|
||||
* @param array<string> $headers list of options
|
||||
* @param array{auth_type:?int,auth_userpwd:?string} $auth_data auth options to override global
|
||||
* @return void
|
||||
*/
|
||||
private function setCurlOptions(\CurlHandle $handle, array $headers): void
|
||||
private function setCurlOptions(\CurlHandle $handle, array $headers, array $auth_data): void
|
||||
{
|
||||
// for not Basic auth, basic auth sets its own header
|
||||
if (!empty($this->auth_type) && !empty($this->auth_userpwd)) {
|
||||
curl_setopt($handle, CURLOPT_HTTPAUTH, $this->auth_type);
|
||||
curl_setopt($handle, CURLOPT_USERPWD, $this->auth_userpwd);
|
||||
// for not Basic auth only, basic auth sets its own header
|
||||
if ($auth_data['auth_type'] !== null || $auth_data['auth_userpwd'] !== null) {
|
||||
// set global if any of the two is empty and both globals are set
|
||||
if (
|
||||
(empty($auth_data['auth_type']) || empty($auth_data['auth_userpwd'])) &&
|
||||
!empty($this->auth_type) && !empty($this->auth_userpwd)
|
||||
) {
|
||||
$auth_data['auth_type'] = $this->auth_type;
|
||||
$auth_data['auth_userpwd'] = $this->auth_userpwd;
|
||||
}
|
||||
}
|
||||
// set auth options for curl
|
||||
if (!empty($auth_data['auth_type']) && !empty($auth_data['auth_userpwd'])) {
|
||||
curl_setopt($handle, CURLOPT_HTTPAUTH, $auth_data['auth_type']);
|
||||
curl_setopt($handle, CURLOPT_USERPWD, $auth_data['auth_userpwd']);
|
||||
}
|
||||
if ($headers !== []) {
|
||||
curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
|
||||
@@ -591,11 +699,12 @@ class Curl implements Interface\RequestsInterface
|
||||
$timeout_requires_no_signal = false;
|
||||
// if we have a timeout signal
|
||||
if (!empty($this->config['timeout'])) {
|
||||
$timeout_requires_no_signal |= $this->config['timeout'] < 1;
|
||||
$timeout_requires_no_signal = $this->config['timeout'] < 1;
|
||||
curl_setopt($handle, CURLOPT_TIMEOUT_MS, $this->config['timeout'] * 1000);
|
||||
}
|
||||
if (!empty($this->config['connection_timeout'])) {
|
||||
$timeout_requires_no_signal |= $this->config['connection_timeout'] < 1;
|
||||
$timeout_requires_no_signal = $timeout_requires_no_signal ||
|
||||
$this->config['connection_timeout'] < 1;
|
||||
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT_MS, $this->config['connection_timeout'] * 1000);
|
||||
}
|
||||
if ($timeout_requires_no_signal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
||||
@@ -665,8 +774,8 @@ class Curl implements Interface\RequestsInterface
|
||||
}
|
||||
|
||||
// throw an error like in the normal reqeust, but set to CURL error
|
||||
throw new RuntimeException(
|
||||
json_encode([
|
||||
throw new \RuntimeException(
|
||||
Json::jsonConvertArrayTo([
|
||||
'status' => 'FAILURE',
|
||||
'code' => 'C002',
|
||||
'type' => 'CurlExecError',
|
||||
@@ -676,7 +785,7 @@ class Curl implements Interface\RequestsInterface
|
||||
'errno' => $errno,
|
||||
'message' => $message,
|
||||
],
|
||||
]) ?: '',
|
||||
]),
|
||||
$errno
|
||||
);
|
||||
}
|
||||
@@ -687,16 +796,17 @@ class Curl implements Interface\RequestsInterface
|
||||
* Handle curl response, will throw exception on anything that is lower 400
|
||||
* can be turned off by setting http_errors to false
|
||||
*
|
||||
* @param string $http_result result string from the url call
|
||||
* @param ?bool $http_errors if we should throw an exception on error, override config setting
|
||||
* @param \CurlHandle $handle Curl handler
|
||||
* @param string $http_result result string from the url call
|
||||
* @param ?bool $http_errors if we should throw an exception on error,
|
||||
* override config setting
|
||||
* @return string http response code
|
||||
* @throws \RuntimeException if http_errors is true then will throw exception on any response code >= 400
|
||||
*/
|
||||
private function handleCurlResponse(
|
||||
\CurlHandle $handle,
|
||||
string $http_result,
|
||||
?bool $http_errors,
|
||||
\CurlHandle $handle
|
||||
?bool $http_errors
|
||||
): string {
|
||||
$http_response = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
|
||||
if (
|
||||
@@ -708,8 +818,8 @@ class Curl implements Interface\RequestsInterface
|
||||
// set curl error number
|
||||
$err = curl_errno($handle);
|
||||
// throw Error here with all codes
|
||||
throw new RuntimeException(
|
||||
json_encode([
|
||||
throw new \RuntimeException(
|
||||
Json::jsonConvertArrayTo([
|
||||
'status' => 'ERROR',
|
||||
'code' => 'H' . (string)$http_response,
|
||||
'type' => $http_response < 500 ? 'ClientError' : 'ServerError',
|
||||
@@ -717,13 +827,13 @@ class Curl implements Interface\RequestsInterface
|
||||
'context' => [
|
||||
'http_response' => $http_response,
|
||||
// extract all the error content if returned
|
||||
'result' => json_decode((string)$http_result, true),
|
||||
'result' => Json::jsonConvertToArray($http_result),
|
||||
// curl internal error number
|
||||
'curl_errno' => $err,
|
||||
// the full curl info block
|
||||
'curl_info' => curl_getinfo($handle),
|
||||
],
|
||||
]) ?: '',
|
||||
]),
|
||||
$err
|
||||
);
|
||||
}
|
||||
@@ -743,48 +853,6 @@ class Curl implements Interface\RequestsInterface
|
||||
// MARK: PUBLIC METHODS
|
||||
// *********************************************************************
|
||||
|
||||
/**
|
||||
* Convert an array with header strings like "foo: bar" to the interface
|
||||
* needed "foo" => "bar" type
|
||||
* Skips entries that are already in key => value type, by checking if the
|
||||
* key is a not a number
|
||||
*
|
||||
* @param array<int|string,string> $headers
|
||||
* @return array<string,string>
|
||||
* @throws \UnexpectedValueException on duplicate header key
|
||||
*/
|
||||
public function prepareHeaders(array $headers): array
|
||||
{
|
||||
$return_headers = [];
|
||||
foreach ($headers as $header_key => $header) {
|
||||
// skip if header key is not numeric
|
||||
if (!is_numeric($header_key)) {
|
||||
$return_headers[$header_key] = $header;
|
||||
continue;
|
||||
}
|
||||
list($_key, $_value) = explode(':', $header);
|
||||
if (array_key_exists($_key, $return_headers)) {
|
||||
// raise exception if key already exists
|
||||
throw new \UnexpectedValueException(
|
||||
json_encode([
|
||||
'status' => 'ERROR',
|
||||
'code' => 'R001',
|
||||
'type' => 'DuplicatedArrayKey',
|
||||
'message' => 'Key already exists in the headers',
|
||||
'context' => [
|
||||
'key' => $_key,
|
||||
'headers' => $headers,
|
||||
'return_headers' => $return_headers,
|
||||
],
|
||||
]) ?: '',
|
||||
1
|
||||
);
|
||||
}
|
||||
$return_headers[$_key] = $_value;
|
||||
}
|
||||
return $return_headers;
|
||||
}
|
||||
|
||||
// MARK: get class vars
|
||||
|
||||
/**
|
||||
@@ -947,7 +1015,7 @@ class Curl implements Interface\RequestsInterface
|
||||
* phpcs:disable Generic.Files.LineLength
|
||||
* @param string $type
|
||||
* @param string $url
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} Result code, headers and content as array, content is json
|
||||
* @throws \UnexpectedValueException on missing body data when body data is needed
|
||||
* phpcs:enable Generic.Files.LineLength
|
||||
@@ -957,20 +1025,15 @@ class Curl implements Interface\RequestsInterface
|
||||
// can have
|
||||
// - headers
|
||||
// - query
|
||||
// - auth: null for no auth at all
|
||||
// - http_errors: false for no exception on http error
|
||||
// depending on type, must have (post/put/patch), optional for (delete)
|
||||
// - body
|
||||
$type = strtolower($type);
|
||||
// check if we need a payload data set, set empty on not set
|
||||
if (in_array($type, self::MANDATORY_POST_FIELDS) && !isset($options['body'])) {
|
||||
$options['body'] = [];
|
||||
}
|
||||
return $this->curlRequest(
|
||||
$type,
|
||||
$url,
|
||||
!array_key_exists('headers', $options) ? [] : $options['headers'],
|
||||
$options['query'] ?? null,
|
||||
$options['body'] ?? null,
|
||||
!array_key_exists('http_errors', $options) ? null : $options['http_errors'],
|
||||
$options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,34 +18,6 @@ namespace CoreLibs\UrlRequests;
|
||||
|
||||
trait CurlTrait
|
||||
{
|
||||
/**
|
||||
* Set the array block that is sent to the request call
|
||||
* Make sure that if headers is set as key but null it stays null and set to empty array
|
||||
* if headers key is missing
|
||||
* "get" calls do not set any body
|
||||
*
|
||||
* @param string $type if set as get do not add body, else add body
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Request options
|
||||
* @return array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool}
|
||||
*/
|
||||
private function setOptions(string $type, array $options): array
|
||||
{
|
||||
if ($type == "get") {
|
||||
return [
|
||||
"headers" => !array_key_exists('headers', $options) ? [] : $options['headers'],
|
||||
"query" => $options['query'] ?? null,
|
||||
"http_errors" => !array_key_exists('http_errors', $options) ? null : $options['http_errors'],
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
"headers" => !array_key_exists('headers', $options) ? [] : $options['headers'],
|
||||
"query" => $options['query'] ?? null,
|
||||
"body" => $options['body'] ?? null,
|
||||
"http_errors" => !array_key_exists('http_errors', $options) ? null : $options['http_errors'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* combined set call for any type of request with options type parameters
|
||||
* The following options can be set:
|
||||
@@ -55,7 +27,7 @@ trait CurlTrait
|
||||
*
|
||||
* @param string $type What type of request we send, will throw exception if not a valid one
|
||||
* @param string $url The url to send
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Request options
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Request options
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} [default=[]] Result code, headers and content as array, content is json
|
||||
* @throws \UnexpectedValueException on missing body data when body data is needed
|
||||
*/
|
||||
@@ -67,7 +39,7 @@ trait CurlTrait
|
||||
*
|
||||
* @param string $url The URL being requested,
|
||||
* including domain and protocol
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} [default=[]] Result code, headers and content as array, content is json
|
||||
*/
|
||||
public function get(string $url, array $options = []): array
|
||||
@@ -75,11 +47,8 @@ trait CurlTrait
|
||||
return $this->request(
|
||||
"get",
|
||||
$url,
|
||||
$this->setOptions('get', $options),
|
||||
$options,
|
||||
);
|
||||
|
||||
// array{headers?: array<string, array<string>|string>|null, query?: array<string, string>|null, body?: array<string, mixed>|string|null},
|
||||
// array{headers?: array<string, array<string>|string>|null, query?: array<string, mixed>|string|null, body?: array<string, mixed>|string|null}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,7 +57,7 @@ trait CurlTrait
|
||||
*
|
||||
* @param string $url The URL being requested,
|
||||
* including domain and protocol
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} Result code, headers and content as array, content is json
|
||||
*/
|
||||
public function post(string $url, array $options): array
|
||||
@@ -96,7 +65,7 @@ trait CurlTrait
|
||||
return $this->request(
|
||||
"post",
|
||||
$url,
|
||||
$this->setOptions('post', $options),
|
||||
$options,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -106,7 +75,7 @@ trait CurlTrait
|
||||
*
|
||||
* @param string $url The URL being requested,
|
||||
* including domain and protocol
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} Result code, headers and content as array, content is json
|
||||
*/
|
||||
public function put(string $url, array $options): array
|
||||
@@ -114,7 +83,7 @@ trait CurlTrait
|
||||
return $this->request(
|
||||
"put",
|
||||
$url,
|
||||
$this->setOptions('put', $options),
|
||||
$options,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -124,7 +93,7 @@ trait CurlTrait
|
||||
*
|
||||
* @param string $url The URL being requested,
|
||||
* including domain and protocol
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} Result code, headers and content as array, content is json
|
||||
*/
|
||||
public function patch(string $url, array $options): array
|
||||
@@ -132,7 +101,7 @@ trait CurlTrait
|
||||
return $this->request(
|
||||
"patch",
|
||||
$url,
|
||||
$this->setOptions('patch', $options),
|
||||
$options,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,7 +112,7 @@ trait CurlTrait
|
||||
*
|
||||
* @param string $url The URL being requested,
|
||||
* including domain and protocol
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options Options to set
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} [default=[]] Result code, headers and content as array, content is json
|
||||
*/
|
||||
public function delete(string $url, array $options = []): array
|
||||
@@ -151,7 +120,7 @@ trait CurlTrait
|
||||
return $this->request(
|
||||
"delete",
|
||||
$url,
|
||||
$this->setOptions('delete', $options),
|
||||
$options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,18 +11,6 @@ namespace CoreLibs\UrlRequests\Interface;
|
||||
|
||||
interface RequestsInterface
|
||||
{
|
||||
/**
|
||||
* Convert an array with header strings like "foo: bar" to the interface
|
||||
* needed "foo" => "bar" type
|
||||
* Skips entries that are already in key => value type, by checking if the
|
||||
* key is a not a number
|
||||
*
|
||||
* @param array<int|string,string> $headers
|
||||
* @return array<string,string>
|
||||
* @throws \UnexpectedValueException on duplicate header key
|
||||
*/
|
||||
public function prepareHeaders(array $headers): array;
|
||||
|
||||
/**
|
||||
* get the config array with all settings
|
||||
*
|
||||
@@ -84,7 +72,7 @@ interface RequestsInterface
|
||||
* phpcs:disable Generic.Files.LineLength
|
||||
* @param string $type
|
||||
* @param string $url
|
||||
* @param array{headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<string,mixed>} $options
|
||||
* @param array{auth?:null|array{0:string,1:string,2:string},headers?:null|array<string,string|array<string>>,query?:null|array<string,string>,body?:null|string|array<mixed>,http_errors?:null|bool} $options
|
||||
* @return array{code:string,headers:array<string,array<string>>,content:string} Result code, headers and content as array, content is json
|
||||
* @throws \UnexpectedValueException on missing body data when body data is needed
|
||||
* phpcs:enable Generic.Files.LineLength
|
||||
Reference in New Issue
Block a user