piwik /core/Tracker/ActionSiteSearch.php

Language PHP Lines 255
MD5 Hash d16cf183d43481979464f49fd2e89553
Repository https://github.com/CodeYellowBV/piwik.git View Raw File View Project SPDX
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
<?php
/**
 * Piwik - free/libre analytics platform
 *
 * @link http://piwik.org
 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 *
 */

namespace Piwik\Tracker;

use Piwik\Common;
use Piwik\Tracker;
use Piwik\UrlHelper;

/**
 * This class represents a search on the site.
 * - Its name is the search keyword
 * - by default the URL is not recorded (since it's not used)
 * - tracks site search result count and site search category as custom variables
 *
 */
class ActionSiteSearch extends Action
{
    private $searchCategory = false;
    private $searchCount = false;

    const CVAR_KEY_SEARCH_CATEGORY = '_pk_scat';
    const CVAR_KEY_SEARCH_COUNT = '_pk_scount';
    const CVAR_INDEX_SEARCH_CATEGORY = '4';
    const CVAR_INDEX_SEARCH_COUNT = '5';


    function __construct($url, Request $request)
    {
        parent::__construct(Action::TYPE_SITE_SEARCH, $request);
        $this->originalUrl = $url;
    }

    protected function getActionsToLookup()
    {
        return array(
            'idaction_name' => array($this->getActionName(), Action::TYPE_SITE_SEARCH),
        );
    }

    public function getIdActionUrl()
    {
        // Site Search, by default, will not track URL. We do not want URL to appear as "Page URL not defined"
        // so we specifically set it to NULL in the table (the archiving query does IS NOT NULL)
        return null;
    }

    public function getCustomFloatValue()
    {
        return $this->request->getPageGenerationTime();
    }

    function isSearchDetected()
    {
        $siteSearch = $this->detectSiteSearch($this->originalUrl);

        if(empty($siteSearch)) {
            return false;
        }

        list($actionName, $url, $category, $count) = $siteSearch;

        if (!empty($category)) {
            $this->searchCategory = trim($category);
        }
        if ($count !== false) {
            $this->searchCount = $count;
        }
        $this->setActionName($actionName);
        $this->setActionUrl($url);

        return true;
    }


    public function getCustomVariables()
    {
        $customVariables = parent::getCustomVariables();

        // Enrich Site Search actions with Custom Variables, overwriting existing values
        if (!empty($this->searchCategory)) {
            if (!empty($customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_CATEGORY])) {
                Common::printDebug("WARNING: Overwriting existing Custom Variable  in slot " . self::CVAR_INDEX_SEARCH_CATEGORY . " for this page view");
            }
            $customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_CATEGORY] = self::CVAR_KEY_SEARCH_CATEGORY;
            $customVariables['custom_var_v' . self::CVAR_INDEX_SEARCH_CATEGORY] = Request::truncateCustomVariable($this->searchCategory);
        }
        if ($this->searchCount !== false) {
            if (!empty($customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_COUNT])) {
                Common::printDebug("WARNING: Overwriting existing Custom Variable  in slot " . self::CVAR_INDEX_SEARCH_COUNT . " for this page view");
            }
            $customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_COUNT] = self::CVAR_KEY_SEARCH_COUNT;
            $customVariables['custom_var_v' . self::CVAR_INDEX_SEARCH_COUNT] = (int)$this->searchCount;
        }
        return $customVariables;
    }

    protected function detectSiteSearchFromUrl($website, $parsedUrl)
    {
        $doRemoveSearchParametersFromUrl = true;
        $separator = '&';
        $count = $actionName = $categoryName = false;

        $keywordParameters = isset($website['sitesearch_keyword_parameters'])
            ? $website['sitesearch_keyword_parameters']
            : array();
        $queryString = (!empty($parsedUrl['query']) ? $parsedUrl['query'] : '') . (!empty($parsedUrl['fragment']) ? $separator . $parsedUrl['fragment'] : '');
        $parametersRaw = UrlHelper::getArrayFromQueryString($queryString);

        // strtolower the parameter names for smooth site search detection
        $parameters = array();
        foreach ($parametersRaw as $k => $v) {
            $parameters[Common::mb_strtolower($k)] = $v;
        }
        // decode values if they were sent from a client using another charset
        $pageEncoding = $this->request->getParam('cs');
        PageUrl::reencodeParameters($parameters, $pageEncoding);

        // Detect Site Search keyword
        foreach ($keywordParameters as $keywordParameterRaw) {
            $keywordParameter = Common::mb_strtolower($keywordParameterRaw);
            if (!empty($parameters[$keywordParameter])) {
                $actionName = $parameters[$keywordParameter];
                break;
            }
        }

        if (empty($actionName)) {
            return false;
        }

        $categoryParameters = isset($website['sitesearch_category_parameters'])
            ? $website['sitesearch_category_parameters']
            : array();

        foreach ($categoryParameters as $categoryParameterRaw) {
            $categoryParameter = Common::mb_strtolower($categoryParameterRaw);
            if (!empty($parameters[$categoryParameter])) {
                $categoryName = $parameters[$categoryParameter];
                break;
            }
        }

        if (isset($parameters['search_count'])
            && $this->isValidSearchCount($parameters['search_count'])
        ) {
            $count = $parameters['search_count'];
        }
        // Remove search kwd from URL
        if ($doRemoveSearchParametersFromUrl) {
            // @see excludeQueryParametersFromUrl()
            // Excluded the detected parameters from the URL
            $parametersToExclude = array($categoryParameterRaw, $keywordParameterRaw);
            if(isset($parsedUrl['query'])) {
                $parsedUrl['query'] = UrlHelper::getQueryStringWithExcludedParameters(UrlHelper::getArrayFromQueryString($parsedUrl['query']), $parametersToExclude);
            }
            if(isset($parsedUrl['fragment'])) {
                $parsedUrl['fragment'] = UrlHelper::getQueryStringWithExcludedParameters(UrlHelper::getArrayFromQueryString($parsedUrl['fragment']), $parametersToExclude);
            }
        }
        $url = UrlHelper::getParseUrlReverse($parsedUrl);
        if (is_array($actionName)) {
            $actionName = reset($actionName);
        }
        $actionName = trim(urldecode($actionName));
        if (empty($actionName)) {
            return false;
        }
        if (is_array($categoryName)) {
            $categoryName = reset($categoryName);
        }
        $categoryName = trim(urldecode($categoryName));
        return array($url, $actionName, $categoryName, $count);
    }

    protected function isValidSearchCount($count)
    {
        return is_numeric($count) && $count >= 0;
    }

    protected function detectSiteSearch($originalUrl)
    {
        $website = Cache::getCacheWebsiteAttributes($this->request->getIdSite());
        if (empty($website['sitesearch'])) {
            Common::printDebug("Internal 'Site Search' tracking is not enabled for this site. ");
            return false;
        }

        $actionName = $url = $categoryName = $count = false;

        $originalUrl = PageUrl::cleanupUrl($originalUrl);

        // Detect Site search from Tracking API parameters rather than URL
        $searchKwd = $this->request->getParam('search');
        if (!empty($searchKwd)) {
            $actionName = $searchKwd;
            $isCategoryName = $this->request->getParam('search_cat');
            if (!empty($isCategoryName)) {
                $categoryName = $isCategoryName;
            }
            $isCount = $this->request->getParam('search_count');
            if ($this->isValidSearchCount($isCount)) {
                $count = $isCount;
            }
        }

        if (empty($actionName)) {
            $parsedUrl = @parse_url($originalUrl);

            // Detect Site Search from URL query parameters
            if (!empty($parsedUrl['query']) || !empty($parsedUrl['fragment'])) {
                // array($url, $actionName, $categoryName, $count);
                $searchInfo = $this->detectSiteSearchFromUrl($website, $parsedUrl);
                if (!empty($searchInfo)) {
                    list ($url, $actionName, $categoryName, $count) = $searchInfo;
                }
            }
        }

        $actionName = trim($actionName);
        $categoryName = trim($categoryName);

        if (empty($actionName)) {
            Common::printDebug("(this is not a Site Search request)");
            return false;
        }

        Common::printDebug("Detected Site Search keyword '$actionName'. ");
        if (!empty($categoryName)) {
            Common::printDebug("- Detected Site Search Category '$categoryName'. ");
        }
        if ($count !== false) {
            Common::printDebug("- Search Results Count was '$count'. ");
        }
        if ($url != $originalUrl) {
            Common::printDebug("NOTE: The Page URL was changed / removed, during the Site Search detection, was '$originalUrl', now is '$url'");
        }

        return array(
            $actionName,
            $url,
            $categoryName,
            $count
        );
    }


}
Back to Top