Hi guys,
I am using CB 2.5.0 on Joomla 3.9.25 running PHP 7.3.22 .
And I think I hit the bug with the CB code.
The problem is that in admin interface of Joomla I am getting following error:
Argument 2 passed to GuzzleHttp\Adapter\StreamAdapter::createResponseObject() must be of the type array, null given, called in <>\libraries\CBLib\GuzzleHttp\Adapter\StreamAdapter.php on line 67
(TypeException is what throw to be exact)
I di some resurch/debugging and it appears that this error is result of CB code combined with PHP 7.3+ parameters checking behavior.
The problem is that in "/libraries/CBLib/GuzzleHttp/Adapter/StreamAdapter.php" , there is a following function:
Code:
private function createResponseObject(
RequestInterface $request,
array $headers,
TransactionInterface $transaction,
StreamInterface $stream
) private function createResponseObject(
RequestInterface $request,
array $headers,
TransactionInterface $transaction,
StreamInterface $stream
)
as you can see the function here accepts "array $headers" as a 2nd parameter, however if we look the code "above the stack", we see:
Code:
private function createResponse(TransactionInterface $transaction)
{
$request = $transaction->getRequest();
$stream = $this->createStream($request, $http_response_header);
$this->createResponseObject(
$request,
$http_response_header,
$transaction,
new Stream($stream)
);
}
The problem here is that while "$this->createStream($request, $http_response_header);" recieves "http_response_header" by reference - nothing inside "createStream" changes it !
Code:
private function createStream(
RequestInterface $request,
&$http_response_header
) {
static $methods;
if (!$methods) {
$methods = array_flip(get_class_methods(__CLASS__));
}
$params = array();
$options = $this->getDefaultOptions($request);
foreach ($request->getConfig()->toArray() as $key => $value) {
$method = "add_{$key}";
if (isset($methods[$method])) {
$this->{$method}($request, $options, $value, $params);
}
}
$this->applyCustomOptions($request, $options);
$context = $this->createStreamContext($request, $options, $params);
return $this->createStreamResource(
$request,
$options,
$context,
$http_response_header
);
}
private function createStreamResource(
RequestInterface $request,
array $options,
$context,
&$http_response_header
) {
$url = $request->getUrl();
return $this->createResource(
function () use ($url, &$http_response_header, $context) {
if (false === strpos($url, 'http')) {
trigger_error("URL is invalid: {$url}", E_USER_WARNING);
return null;
}
return fopen($url, 'r', null, $context);
},
$request,
$options
);
}
[code]
As result the "$http_response_header" remains [b]null[/b] , NOT [b]array[/b] and thats what triggers the TypeException is PHP.
So , of course it's possible to disable PHP type checking in PHP config, but one way or another it's looks like a bug, so it should either be created as empty array, returned as empty artray.
Something like:
[code]
private function createStreamResource(
RequestInterface $request,
array $options,
$context,
&$http_response_header
) {
$url = $request->getUrl();
return $this->createResource(
function () use ($url, &$http_response_header, $context) {
if (false === strpos($url, 'http')) {
trigger_error("URL is invalid: {$url}", E_USER_WARNING);
return null;
}
$http_response_header = array();
return fopen($url, 'r', null, $context);
},
$request,
$options
);
}
Changing "createResponseObject" signature should be changed to something like this:
Code:
private function createResponseObject(
RequestInterface $request,
[b]?array[/b] $headers,
TransactionInterface $transaction,
StreamInterface $stream
) private function createResponseObject(
RequestInterface $request,
array $headers,
TransactionInterface $transaction,
StreamInterface $stream
)
is WRONG as we will get simulart exceptions down the path.