diff --git a/lib/CommunicationAdapter.php b/lib/CommunicationAdapter.php index 7b90bf8..f841216 100644 --- a/lib/CommunicationAdapter.php +++ b/lib/CommunicationAdapter.php @@ -3,6 +3,13 @@ use Checkdomain\Comodo\Model\Account; use GuzzleHttp\Client; +use GuzzleHttp\HandlerStack; +use GuzzleHttp\MessageFormatter; +use GuzzleHttp\Middleware; +use Psr\Http\Message\ResponseInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; /** * Class CommunicationAdapter @@ -24,6 +31,21 @@ class CommunicationAdapter */ protected $account; + /** + * @var LoggerInterface + */ + protected $logger; + + /** + * @var HandlerStack + */ + protected $handlerStack; + + /** + * @var array + */ + protected $denyList; + /** * @param \Checkdomain\Comodo\Model\Account $account * @@ -44,14 +66,18 @@ public function getAccount() return $this->account; } - /** - * Constructs a communication adapter with an account - * - * @param Account $account - */ - public function __construct(Account $account = null) + public function __construct(Account $account = null, LoggerInterface $logger = null, array $denyList = []) { $this->account = $account; + $this->denyList = $denyList; + $this->handlerStack = HandlerStack::create(); + + if ($logger) { + $this->logger = $logger; + $this->handlerStack = $this->addLogMiddleware($this->handlerStack); + } else { + $this->logger = new NullLogger(); + } } /** @@ -72,7 +98,7 @@ public function setClient($client) public function getClient() { if ($this->client === null) { - $this->client = new Client(); + $this->client = new Client(['handler' => $this->handlerStack]); } return $this->client; @@ -281,4 +307,30 @@ protected function decodeUrlEncodedResponse( return $responseArray; } + + protected function addLogMiddleware(HandlerStack $handlerStack) + { + $handlerStack->push( + Middleware::mapResponse( + function (ResponseInterface $response) { + $response->getBody()->rewind(); + + return $response; + } + ) + ); + + $handlerStack->push( + Middleware::log( + $this->logger, + new SanitizingMessageFormatter( + '{method} {uri} HTTP/{version} - Body: {req_body} | {code} - Body: {res_body}', + $this->denyList + ), + LogLevel::DEBUG + ) + ); + + return $handlerStack; + } } diff --git a/lib/SanitizingMessageFormatter.php b/lib/SanitizingMessageFormatter.php new file mode 100644 index 0000000..5dd79fa --- /dev/null +++ b/lib/SanitizingMessageFormatter.php @@ -0,0 +1,130 @@ +template = $template; + $this->blacklist = $denyList; + } + + /** + * @param RequestInterface $request + * @param ResponseInterface|null $response + * @param \Exception|null $error + * + * @return string|string[]|null + */ + public function format(RequestInterface $request, ResponseInterface $response = null, \Exception $error = null) + { + $cache = []; + + return preg_replace_callback( + '/{\s*([A-Za-z_\-\.0-9]+)\s*}/', + function (array $matches) use ($request, $response, $error, &$cache) { + if (isset($cache[$matches[1]])) { + return $cache[$matches[1]]; + } + + $result = ''; + switch ($matches[1]) { + case 'req_body': + $result = $this->sanitizeBody($request->getBody()); + break; + case 'res_body': + $result = $response ? $this->sanitizeBody($response->getBody()) : 'NULL'; + break; + case 'method': + $result = $request->getMethod(); + break; + case 'version': + $result = $request->getProtocolVersion(); + break; + case 'uri': + case 'url': + $result = $request->getUri(); + break; + case 'code': + $result = $response ? $response->getStatusCode() : 'NULL'; + break; + } + + $cache[$matches[1]] = $result; + + return $result; + }, + $this->template + ); + } + + /** + * @param StreamInterface $body + * + * @return string + */ + private function sanitizeBody(StreamInterface $body) + { + $body->rewind(); + $content = $body->getContents(); + + if (false === empty($content)) { + $parsed = []; + parse_str($content, $parsed); + + if (is_array($parsed)) { + $parsed = $this->sanitize($parsed); + } + } + + return false === empty($parsed) ? http_build_query($parsed) : ''; + } + + /** + * @param array $iterable + * + * @return array + */ + private function sanitize(array $iterable) + { + $filtered = []; + + foreach ($iterable as $key => $item) { + if (is_string($key) && is_string($item)) { + if (in_array($key, $this->blacklist)) { + $item = 'sanitized'; + } + } + + if (is_array($item)) { + $item = $this->sanitize($item); + } + + $filtered[$key] = $item; + } + + return $filtered; + } +}