Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
81.82% covered (warning)
81.82%
9 / 11
CRAP
93.59% covered (success)
93.59%
73 / 78
RequestDumpListener
0.00% covered (danger)
0.00%
0 / 1
81.82% covered (warning)
81.82%
9 / 11
29.22
93.59% covered (success)
93.59%
73 / 78
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 onKernelRequest
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
11 / 11
 onResponse
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
13 / 13
 getSubscribedEvents
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 addExcludeKey
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 removeExcludeKey
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 logRequest
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
19 / 19
 logResponse
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 logSession
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 logArray
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
4 / 4
 logKeyValuePair
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
18 / 18
<?php
namespace Eccube\EventListener;
use Eccube\Application;
use Monolog\Logger;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
 * リクエストログ出力ため Listener
 *
 * ログ出力を除外したいキーは log.yml の exclude_keys で設定します.
 * addExcludeKey(), removeExcludeKey() でも設定できます.
 *
 * @author Kentaro Ohkouchi
 */
class RequestDumpListener implements EventSubscriberInterface
{
    private $app;
    private $excludeKeys;
    /**
     * Constructor function.
     *
     * @param Application $app
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
        $this->excludeKeys = $app['config']['log']['exclude_keys'];
    }
    /**
     * Kernel request listener callback.
     *
     * @param GetResponseEvent $event
     */
    public function onKernelRequest(GetResponseEvent $event)
    {
        if (!$event->isMasterRequest()) {
            return;
        }
        $log = '** before *****************************************:'.PHP_EOL;
        $request = $event->getRequest();
        $log .= $this->logRequest($request);
        $Session = $request->getSession();
        if ($request->hasSession()) {
            $log .= $this->logSession($Session);
        }
        $this->app->log($log, array(), Logger::DEBUG);
        log_debug($log);
    }
    /**
     * Kernel response listener callback.
     *
     * @param FilterResponseEvent $event
     */
    public function onResponse(FilterResponseEvent $event)
    {
        if (!$event->isMasterRequest()) {
            return;
        }
        $log = '** after *****************************************:'.PHP_EOL;
        $response = $event->getResponse();
        $log .= $this->logResponse($response);
        $request = $event->getRequest();
        $log .= $this->logRequest($request);
        $Session = $request->getSession();
        if ($request->hasSession()) {
            $log .= $this->logSession($Session);
        }
        $this->app->log($log, array(), Logger::DEBUG);
        log_debug($log);
    }
    /**
     * Return the events to subscribe to.
     *
     * @return array
     */
    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::REQUEST => 'onKernelRequest',
            KernelEvents::RESPONSE => 'onResponse',
        );
    }
    /**
     * ログ出力を除外するキーを追加します.
     *
     * @param string $key 除外対象のキー
     */
    protected function addExcludeKey($key)
    {
        $this->excludeKeys[] = $key;
    }
    /**
     * ログ出力を除外するキーを削除します.
     *
     * @param string $key 削除対象のキー
     */
    protected function removeExcludeKey($key)
    {
        if (array_key_exists($key, $this->excludeKeys)) {
            unset($this->excludeKeys[$key]);
        }
    }
    /**
     * Request のログを出力する.
     *
     * @param Request $request
     * @return string Request のログ
     */
    protected function logRequest(Request $request)
    {
        $log = '';
        $log .= $this->logKeyValuePair('REMOTE_ADDR', $request->getClientIp());
        $log .= $this->logKeyValuePair('SCRIPT_NAME', $request->getScriptName());
        $log .= $this->logKeyValuePair('PATH_INFO', $request->getPathInfo());
        $log .= $this->logKeyValuePair('BASE_PATH', $request->getBasePath());
        $log .= $this->logKeyValuePair('BASE_URL', $request->getBaseUrl());
        $log .= $this->logKeyValuePair('SCHEME', $request->getScheme());
        $log .= $this->logKeyValuePair('REMOTE_USER', $request->getUser());
        $log .= $this->logKeyValuePair('HTTP_HOST', $request->getSchemeAndHttpHost());
        $log .= $this->logKeyValuePair('REQUEST_URI', $request->getRequestUri());
        $log .= $this->logKeyValuePair('METHOD', $request->getRealMethod());
        $log .= $this->logKeyValuePair('LOCALE', $request->getLocale());
        // $log .= $this->logArray($request->server->all(), '[server]'); // 大量にログ出力される...
        $log .= $this->logArray($request->headers->all(), '[header]');
        $log .= $this->logArray($request->query->all(), '[get]');
        $log .= $this->logArray($request->request->all(), '[post]');
        $log .= $this->logArray($request->attributes->all(), '[attributes]');
        $log .= $this->logArray($request->cookies->all(), '[cookie]');
        $log .= $this->logArray($request->files->all(), '[files]');
        return $log;
    }
    /**
     * Response のログを出力する.
     *
     * @param Response $response
     * @return string Response のログ
     */
    protected function logResponse(Response $response)
    {
        $log = '';
        $log .= $this->logKeyValuePair('HTTP_STATUS', $response->getStatusCode());
        return $log;
    }
    /**
     * Session のログを出力する.
     */
    protected function logSession(SessionInterface $Session)
    {
        return $this->logArray($Session->all(), '[session]');
    }
    /**
     * 配列をログ出力する.
     */
    protected function logArray(array $values, $prefix = '')
    {
        $log = '';
        foreach ($values as $key => $val) {
            $log .= $this->logKeyValuePair($key, $val, $prefix);
        }
        return $log;
    }
    /**
     * キーと値のペアをログ出力する.
     *
     * 除外キーに該当する値は, マスクをかける
     */
    protected function logKeyValuePair($key, $value, $prefix = '')
    {
        if (in_array($key, $this->excludeKeys)) {
            return '';
        }
        if (is_null($value) || is_scalar($value) || (is_object($value) && method_exists($value, '__toString'))) {
            $copy_value = $value;
        } elseif (is_object($value)) {
            try {
                $copy_value = '[object '.serialize($value).']';
            } catch (\Exception $e) {
                return $e->getMessage().PHP_EOL;
            }
        } else {
            $copy_value = $value;
            if (is_array($copy_value)) {
                foreach ($copy_value as $key => &$val) {
                    if (in_array($key, $this->excludeKeys)
                        && $prefix != '[header]') { // XXX header にもマスクがかかってしまう
                        $val = '******';
                    }
                }
            }
            try {
                $copy_value = '['.serialize($copy_value).']';
            } catch (\Exception $e) {
                return $e->getMessage().PHP_EOL;
            }
        }
        return '  '.$prefix.' '.$key.'='.$copy_value.PHP_EOL;
    }
}