Completed
Push — master ( 2529b9...694264 )
by Timo
13:23
created

StatisticsWriter   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 5

Test Coverage

Coverage 58.33%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 14
lcom 0
cbo 5
dl 0
loc 113
ccs 42
cts 72
cp 0.5833
rs 10
c 1
b 0
f 1

3 Methods

Rating   Name   Duplication   Size   Complexity  
A sanitizeString() 0 10 1
B applyIpMask() 0 24 4
C processResponse() 0 54 9
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Response\Processor;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2009-2015 Ingo Renner <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use ApacheSolrForTypo3\Solr\Query;
28
use ApacheSolrForTypo3\Solr\Util;
29
use ApacheSolrForTypo3\Solr\HtmlContentExtractor;
30
use TYPO3\CMS\Core\Utility\GeneralUtility;
31
32
/**
33
 * Writes statistics after searches have been conducted.
34
 *
35
 * @author Ingo Renner <[email protected]>
36
 * @author Dimitri Ebert <[email protected]>
37
 */
38
class StatisticsWriter implements ResponseProcessor
39
{
40
41
    /**
42
     * Processes a query and its response after searching for that query.
43
     *
44
     * @param Query $query The query that has been searched for.
45
     * @param \Apache_Solr_Response $response The response for the last query.
46
     */
47 20
    public function processResponse(
48
        Query $query,
49
        \Apache_Solr_Response $response
50
    ) {
51 20
        $urlParameters = GeneralUtility::_GP('tx_solr');
52 20
        $keywords = $query->getKeywords();
53 20
        $filters = isset($urlParameters['filter']) ? $urlParameters['filter'] : array();
54
55 20
        if (empty($keywords)) {
56
            // do not track empty queries
57 2
            return;
58
        }
59
60 18
        $keywords = $this->sanitizeString($keywords);
61
62 18
        $sorting = '';
63 18
        if (!empty($urlParameters['sort'])) {
64 1
            $sorting = $this->sanitizeString($urlParameters['sort']);
65
        }
66
67 18
        $configuration = Util::getSolrConfiguration();
68 18
        if ($configuration->getSearchFrequentSearchesUseLowercaseKeywords()) {
69
            $keywords = strtolower($keywords);
70
        }
71
72 18
        $ipMaskLength = $configuration->getStatisticsAnonymizeIP();
73
74
        $insertFields = array(
75 18
            'pid' => $GLOBALS['TSFE']->id,
76 18
            'root_pid' => $GLOBALS['TSFE']->tmpl->rootLine[0]['uid'],
77 18
            'tstamp' => $GLOBALS['EXEC_TIME'],
78 18
            'language' => $GLOBALS['TSFE']->sys_language_uid,
79
80 18
            'num_found' => $response->response->numFound,
81 18
            'suggestions_shown' => is_object($response->spellcheck->suggestions) ? (int)get_object_vars($response->spellcheck->suggestions) : 0,
82 18
            'time_total' => isset($response->debug->timing->time) ? $response->debug->timing->time : 0,
83 18
            'time_preparation' => isset($response->debug->timing->prepare->time) ? $response->debug->timing->prepare->time : 0,
84 18
            'time_processing' => isset($response->debug->timing->process->time) ? $response->debug->timing->process->time : 0,
85
86 18
            'feuser_id' => (int)$GLOBALS['TSFE']->fe_user->user['uid'],
87 18
            'cookie' => $GLOBALS['TSFE']->fe_user->id,
88 18
            'ip' => $this->applyIpMask(GeneralUtility::getIndpEnv('REMOTE_ADDR'),
89
                $ipMaskLength),
90
91 18
            'page' => (int)$urlParameters['page'],
92 18
            'keywords' => $keywords,
93 18
            'filters' => serialize($filters),
94 18
            'sorting' => $sorting,
95 18
            'parameters' => serialize($response->responseHeader->params)
96
        );
97
98 18
        $GLOBALS['TYPO3_DB']->exec_INSERTquery('tx_solr_statistics',
99
            $insertFields);
100 18
    }
101
102
    /**
103
     * Sanitizes a string
104
     *
105
     * @param $string String to sanitize
106
     * @return string Sanitized string
107
     */
108 18
    protected function sanitizeString($string)
109
    {
110
        // clean content
111 18
        $string = HtmlContentExtractor::cleanContent($string);
112 18
        $string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
113 18
        $string = filter_var(strip_tags($string), FILTER_SANITIZE_STRING); // after entity decoding we might have tags again
114 18
        $string = trim($string);
115
116 18
        return $string;
117
    }
118
119
    /**
120
     * Internal function to mask portions of the visitor IP address
121
     *
122
     * @param string $ip IP address in network address format
123
     * @param int $maskLength Number of octets to reset
124
     * @return string
125
     */
126 18
    protected function applyIpMask($ip, $maskLength)
127
    {
128
        // IPv4 or mapped IPv4 in IPv6
129 18
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
130
            $i = strlen($ip);
131
            if ($maskLength > $i) {
132
                $maskLength = $i;
133
            }
134
135
            while ($maskLength-- > 0) {
136
                $ip[--$i] = chr(0);
137
            }
138
        } else {
139
            $masks = array(
140 18
                'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
141
                'ffff:ffff:ffff:ffff::',
142
                'ffff:ffff:ffff:0000::',
143
                'ffff:ff00:0000:0000::'
144
            );
145 18
            return $ip & pack('a16', inet_pton($masks[$maskLength]));
146
        }
147
148
        return $ip;
149
    }
150
}
151