<?php
/**
 * Request logger
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is protected by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2015 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\WebserviceBundle\EventListener;

use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Log xml request
 */
class WsLoggerListener implements EventSubscriberInterface
{

    /**
     * The logger
     *
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * Constructor
     *
     * @param LoggerInterface $logger
     */
    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    /**
     * Log webservice request
     *
     * @param GetResponseEvent $event
     */
    public function onControllerRequest(GetResponseEvent $event)
    {
        // Log xml requests only
        $request = $event->getRequest();
        if ('xml' !== $request->getContentType() && 0 !== stripos($request->getContent(), '<?xml')) {
            return;
        }

        // Log response
        try {
            $nonUtf8Chars = $this->countNonUtf8Characters($event->getRequest()->getContent());
            $this->logger->debug('Webservice request-encoding: ' . mb_detect_encoding($event->getRequest()->getContent()) . ' (Non UTF-8 characters: ' . $nonUtf8Chars . ')');
            $this->logger->info('Webservice request: ' . $event->getRequest()->getContent());
        } catch (\Exception $ex) {

        }
    }

    /**
     * Log webservice response
     *
     * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
     */
    public function onControllerResponse(FilterResponseEvent $event)
    {
        // Do log response outside webservice
        $request = $event->getRequest();
        if (!$configuration = $request->attributes->get('_wsRoute')) {
            return;
        }

        // Log response
        try {
            $this->logger->info('Webservice response: ' . $event->getResponse()->getContent());
        } catch (\Exception $ex) {

        }
    }

    /**
     * Count number of non-utf8-characters
     *
     * @param string $string
     * @return int
     */
    private function countNonUtf8Characters($string)
    {
        $regex = '/(
    [\xC0-\xC1] # Invalid UTF-8 Bytes
    | [\xF5-\xFF] # Invalid UTF-8 Bytes
    | \xE0[\x80-\x9F] # Overlong encoding of prior code point
    | \xF0[\x80-\x8F] # Overlong encoding of prior code point
    | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
    | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
    | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
    | (?<=[\x0-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
    | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
    | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
    | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
    | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
)/x';
        return preg_match($regex, $string);
    }

    /**
     * Returns list of subscribed events
     *
     * @return array
     */
    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::REQUEST => ['onControllerRequest', -1],
            KernelEvents::RESPONSE => ['onControllerResponse', -1]
        );
    }

}
