D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
tattooscyy
/
test
/
app
/
Libs
/
Sdk
/
Communication
/
Filename :
DefaultConnection.php
back
Copy
<?php namespace App\Libs\Sdk\Communication; use App\Libs\Sdk\CommunicatorConfiguration; use App\Libs\Sdk\Logging\BodyObfuscator; use App\Libs\Sdk\Logging\CommunicatorLogger; use App\Libs\Sdk\Logging\HeaderObfuscator; use App\Libs\Sdk\ProxyConfiguration; use ErrorException; use Exception; use Robtimus\Multipart\MultipartFormData; use UnexpectedValueException; /** * Class ApiException * * @package OnlinePayments\Sdk\Communication */ class DefaultConnection implements Connection { /** @var resource|null */ protected $multiHandle = null; /** @var CommunicatorLogger|null */ protected ?CommunicatorLogger $communicatorLogger = null; /** @var CommunicatorLoggerHelper|null */ private ?CommunicatorLoggerHelper $communicatorLoggerHelper = null; /** @var int */ private int $connectTimeout = -1; /** @var int */ private int $readTimeout = -1; /** @var ProxyConfiguration|null */ private ?ProxyConfiguration $proxyConfiguration = null; /** * @param CommunicatorConfiguration|null $communicatorConfiguration */ public function __construct(?CommunicatorConfiguration $communicatorConfiguration = null) { if ($communicatorConfiguration) { $this->connectTimeout = $communicatorConfiguration->getConnectTimeout(); $this->readTimeout = $communicatorConfiguration->getReadTimeout(); $this->proxyConfiguration = $communicatorConfiguration->getProxyConfiguration(); } } /** * */ public function __destruct() { if (!is_null($this->multiHandle)) { curl_multi_close($this->multiHandle); $this->multiHandle = null; } } /** * @param string $requestUri * @param string[] $requestHeaders * @param callable $responseHandler Callable accepting the response status code, a response body chunk and the response headers */ public function get(string $requestUri, array $requestHeaders, callable $responseHandler): void { $requestId = UuidGenerator::generatedUuid(); $this->logRequest($requestId, 'GET', $requestUri, $requestHeaders); try { $response = $this->executeRequest('GET', $requestUri, $requestHeaders, '', $responseHandler); if ($response) { $this->logResponse($requestId, $requestUri, $response); } } catch (Exception $exception) { $this->logException($requestId, $requestUri, $exception); throw $exception; } } /** * @param string $requestUri * @param string[] $requestHeaders * @param callable $responseHandler Callable accepting the response status code, a response body chunk and the response headers */ public function delete(string $requestUri, array $requestHeaders, callable $responseHandler): void { $requestId = UuidGenerator::generatedUuid(); $this->logRequest($requestId, 'DELETE', $requestUri, $requestHeaders); try { $response = $this->executeRequest('DELETE', $requestUri, $requestHeaders, '', $responseHandler); if ($response) { $this->logResponse($requestId, $requestUri, $response); } } catch (Exception $exception) { $this->logException($requestId, $requestUri, $exception); throw $exception; } } /** * @param string $requestUri * @param string[] $requestHeaders * @param string|MultipartFormDataObject $body * @param callable $responseHandler Callable accepting the response status code, a response body chunk and the response headers */ public function post(string $requestUri, array $requestHeaders, $body, callable $responseHandler): void { $requestId = UuidGenerator::generatedUuid(); $bodyToLog = is_string($body) ? $body : '<binary content>'; $this->logRequest($requestId, 'POST', $requestUri, $requestHeaders, $bodyToLog); try { $response = $this->executeRequest('POST', $requestUri, $requestHeaders, $body, $responseHandler); if ($response) { $this->logResponse($requestId, $requestUri, $response); } } catch (Exception $exception) { $this->logException($requestId, $requestUri, $exception); throw $exception; } } /** * @param string $requestUri * @param string[] $requestHeaders * @param string $body * @param callable $responseHandler Callable accepting the response status code, a response body chunk and the response headers */ public function put(string $requestUri, array $requestHeaders, $body, callable $responseHandler): void { $requestId = UuidGenerator::generatedUuid(); $bodyToLog = is_string($body) ? $body : '<binary content>'; $this->logRequest($requestId, 'PUT', $requestUri, $requestHeaders, $bodyToLog); try { $response = $this->executeRequest('PUT', $requestUri, $requestHeaders, $body, $responseHandler); if ($response) { $this->logResponse($requestId, $requestUri, $response); } } catch (Exception $exception) { $this->logException($requestId, $requestUri, $exception); throw $exception; } } /** * @param CommunicatorLogger $communicatorLogger */ public function enableLogging(CommunicatorLogger $communicatorLogger): void { $this->communicatorLogger = $communicatorLogger; } /** * */ public function disableLogging(): void { $this->communicatorLogger = null; } /** * @param string $httpMethod * @param string $requestUri * @param string[] $requestHeaders * @param string|MultipartFormDataObject $body * @param callable $responseHandler Callable accepting the response status code, a response body chunk and the response headers * @return ConnectionResponseInterface|null * @throws ErrorException */ protected function executeRequest( string $httpMethod, string $requestUri, array $requestHeaders, $body, callable $responseHandler ): ?ConnectionResponse { if (!in_array($httpMethod, array('GET', 'DELETE', 'POST', 'PUT'))) { throw new UnexpectedValueException(sprintf('Http method \'%s\' is not supported', $httpMethod)); } $curlHandle = $this->getCurlHandle(); $this->setCurlOptions($curlHandle, $httpMethod, $requestUri, $requestHeaders, $body); return $this->executeCurlHandle($curlHandle, $responseHandler); } /** * @return resource * @throws ErrorException */ protected function getCurlHandle() { // @phpstan-ignore-next-line if (!$curlHandle = curl_init()) { throw new ErrorException('Cannot initialize cUrl curlHandle'); } return $curlHandle; } /** * @param resource $multiHandle * @param resource $curlHandle * @throws ErrorException */ private function executeCurlHandleShared($multiHandle, $curlHandle): void { $running = 0; do { $status = curl_multi_exec($multiHandle, $running); if ($status > CURLM_OK) { $errorMessage = 'cURL error ' . $status; if (function_exists('curl_multi_strerror')) { $errorMessage .= ' (' . curl_multi_strerror($status) . ')'; } throw new ErrorException($errorMessage); } $info = curl_multi_info_read($multiHandle); if ($info && isset($info['result']) && $info['result'] != CURLE_OK) { $errorMessage = 'cURL error ' . $info['result']; if (function_exists('curl_strerror')) { $errorMessage .= ' (' . curl_strerror($info['result']) . ')'; } throw new ErrorException($errorMessage); } curl_multi_select($multiHandle); } while ($running > 0); } /** * @param resource $curlHandle * @param callable $responseHandler * @return ConnectionResponseInterface|null * @throws Exception */ private function executeCurlHandle($curlHandle, callable $responseHandler): ?ConnectionResponse { $multiHandle = $this->getCurlMultiHandle(); curl_multi_add_handle($multiHandle, $curlHandle); $headerBuilder = new ResponseHeaderBuilder(); $headerFunction = function ($ch, $data) use ($headerBuilder) { $headerBuilder->append($data); return strlen($data); }; $responseBuilder = $this->communicatorLogger ? new ResponseBuilder() : null; $writeFunction = function ($ch, $data) use ($headerBuilder, $responseBuilder, $responseHandler) { $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $headers = $headerBuilder->getHeaders(); call_user_func($responseHandler, $httpStatusCode, $data, $headers); if ($responseBuilder) { $responseBuilder->setHttpStatusCode($httpStatusCode); $responseBuilder->setHeaders($headers); if ($this->isBinaryResponse($headerBuilder)) { $responseBuilder->setBody('<binary content>'); } else { $responseBuilder->appendBody($data); } } return strlen($data); }; curl_setopt($curlHandle, CURLOPT_HEADERFUNCTION, $headerFunction); curl_setopt($curlHandle, CURLOPT_WRITEFUNCTION, $writeFunction); try { $this->executeCurlHandleShared($multiHandle, $curlHandle); // always emit an empty chunk, to make sure that the status code and headers are sent, // even if there is no response body call_user_func($writeFunction, $curlHandle, ''); curl_multi_remove_handle($multiHandle, $curlHandle); return $responseBuilder ? $responseBuilder->getResponse() : null; } catch (Exception $e) { curl_multi_remove_handle($multiHandle, $curlHandle); throw $e; } } /** * @param resource $curlHandle * @param string $httpMethod * @param string $requestUri * @param string[] $requestHeaders * @param string|MultipartFormDataObject $body */ protected function setCurlOptions( $curlHandle, string $httpMethod, string $requestUri, array $requestHeaders, $body ): void { curl_setopt($curlHandle, CURLOPT_HEADER, false); curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true); curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, $httpMethod); curl_setopt($curlHandle, CURLOPT_URL, $requestUri); if ($this->connectTimeout > 0) { curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout); } if ($this->readTimeout > 0) { curl_setopt($curlHandle, CURLOPT_TIMEOUT, $this->readTimeout); } if (in_array($httpMethod, array('PUT', 'POST')) && $body) { if (is_string($body)) { curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $body); } elseif ($body instanceof MultipartFormDataObject) { $multipart = new MultipartFormData($body->getBoundary()); foreach ($body->getValues() as $name => $value) { $multipart->addValue($name, $value); } foreach ($body->getFiles() as $name => $file) { $multipart->addFile($name, $file->getFileName(), $file->getContent(), $file->getContentType(), $file->getContentLength()); } $multipart->finish(); $contentLength = $multipart->getContentLength(); if ($contentLength >= 0) { $requestHeaders[] = 'Content-Length: ' . $contentLength; } curl_setopt($curlHandle, CURLOPT_READFUNCTION, array($multipart, 'curl_read')); curl_setopt($curlHandle, CURLOPT_UPLOAD, true); } else { $type = is_object($body) ? get_class($body) : gettype($body); throw new UnexpectedValueException('Unsupported body type: ' . $type); } } if (!empty($requestHeaders)) { curl_setopt($curlHandle, CURLOPT_HTTPHEADER, HttpHeaderHelper::generateRawHeaders($requestHeaders)); } if (!is_null($this->proxyConfiguration)) { $curlProxy = $this->proxyConfiguration->getCurlProxy(); if (!empty($curlProxy)) { curl_setopt($curlHandle, CURLOPT_PROXY, $curlProxy); } $curlProxyUserPwd = $this->proxyConfiguration->getCurlProxyUserPwd(); if (!empty($curlProxyUserPwd)) { curl_setopt($curlHandle, CURLOPT_PROXYUSERPWD, $curlProxyUserPwd); } } } /** * @return resource * @throws Exception */ private function getCurlMultiHandle() { if (is_null($this->multiHandle)) { $multiHandle = curl_multi_init(); if ($multiHandle === false) { throw new ErrorException('Failed to initialize cURL multi curlHandle'); } $this->multiHandle = $multiHandle; } return $this->multiHandle; } /** * @return bool */ private function isBinaryResponse(ResponseHeaderBuilder $headerBuilder): bool { $contentType = $headerBuilder->getContentType(); return $contentType // does not start with text/ && strrpos($contentType, 'text/', -strlen($contentType)) === false // does not contain json && strrpos($contentType, 'json') === false // does not contain xml && strrpos($contentType, 'xml') === false; } /** * @param string $requestId * @param string $requestMethod * @param string $requestUri * @param array $requestHeaders * @param string $requestBody */ protected function logRequest( string $requestId, string $requestMethod, string $requestUri, array $requestHeaders, $requestBody = '' ): void { if ($this->communicatorLogger) { $this->getCommunicatorLoggerHelper()->logRequest( $this->communicatorLogger, $requestId, $requestMethod, $requestUri, $requestHeaders, $requestBody ); } } /** * @param string $requestId * @param string $requestUri * @param ConnectionResponseInterface $response */ protected function logResponse(string $requestId, string $requestUri, ConnectionResponseInterface $response): void { if ($this->communicatorLogger) { $this->getCommunicatorLoggerHelper()->logResponse( $this->communicatorLogger, $requestId, $requestUri, $response ); } } /** * @param string $requestId * @param string $requestUri * @param Exception $exception */ protected function logException(string $requestId, string $requestUri, Exception $exception): void { if ($this->communicatorLogger) { $this->getCommunicatorLoggerHelper()->logException( $this->communicatorLogger, $requestId, $requestUri, $exception ); } } /** @return CommunicatorLoggerHelper */ protected function getCommunicatorLoggerHelper(): CommunicatorLoggerHelper { if (is_null($this->communicatorLoggerHelper)) { $this->communicatorLoggerHelper = new CommunicatorLoggerHelper; } return $this->communicatorLoggerHelper; } /** * @param BodyObfuscator $bodyObfuscator */ public function setBodyObfuscator(BodyObfuscator $bodyObfuscator): void { $this->getCommunicatorLoggerHelper()->setBodyObfuscator($bodyObfuscator); } /** * @param HeaderObfuscator $headerObfuscator */ public function setHeaderObfuscator(HeaderObfuscator $headerObfuscator): void { $this->getCommunicatorLoggerHelper()->setHeaderObfuscator($headerObfuscator); } }