PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/core/Tracker/ActionSiteSearch.php

https://github.com/CodeYellowBV/piwik
PHP | 254 lines | 190 code | 38 blank | 26 comment | 35 complexity | d16cf183d43481979464f49fd2e89553 MD5 | raw file
Possible License(s): LGPL-3.0, JSON, MIT, GPL-3.0, LGPL-2.1, GPL-2.0, AGPL-1.0, BSD-2-Clause, BSD-3-Clause
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik\Tracker;
  10. use Piwik\Common;
  11. use Piwik\Tracker;
  12. use Piwik\UrlHelper;
  13. /**
  14. * This class represents a search on the site.
  15. * - Its name is the search keyword
  16. * - by default the URL is not recorded (since it's not used)
  17. * - tracks site search result count and site search category as custom variables
  18. *
  19. */
  20. class ActionSiteSearch extends Action
  21. {
  22. private $searchCategory = false;
  23. private $searchCount = false;
  24. const CVAR_KEY_SEARCH_CATEGORY = '_pk_scat';
  25. const CVAR_KEY_SEARCH_COUNT = '_pk_scount';
  26. const CVAR_INDEX_SEARCH_CATEGORY = '4';
  27. const CVAR_INDEX_SEARCH_COUNT = '5';
  28. function __construct($url, Request $request)
  29. {
  30. parent::__construct(Action::TYPE_SITE_SEARCH, $request);
  31. $this->originalUrl = $url;
  32. }
  33. protected function getActionsToLookup()
  34. {
  35. return array(
  36. 'idaction_name' => array($this->getActionName(), Action::TYPE_SITE_SEARCH),
  37. );
  38. }
  39. public function getIdActionUrl()
  40. {
  41. // Site Search, by default, will not track URL. We do not want URL to appear as "Page URL not defined"
  42. // so we specifically set it to NULL in the table (the archiving query does IS NOT NULL)
  43. return null;
  44. }
  45. public function getCustomFloatValue()
  46. {
  47. return $this->request->getPageGenerationTime();
  48. }
  49. function isSearchDetected()
  50. {
  51. $siteSearch = $this->detectSiteSearch($this->originalUrl);
  52. if(empty($siteSearch)) {
  53. return false;
  54. }
  55. list($actionName, $url, $category, $count) = $siteSearch;
  56. if (!empty($category)) {
  57. $this->searchCategory = trim($category);
  58. }
  59. if ($count !== false) {
  60. $this->searchCount = $count;
  61. }
  62. $this->setActionName($actionName);
  63. $this->setActionUrl($url);
  64. return true;
  65. }
  66. public function getCustomVariables()
  67. {
  68. $customVariables = parent::getCustomVariables();
  69. // Enrich Site Search actions with Custom Variables, overwriting existing values
  70. if (!empty($this->searchCategory)) {
  71. if (!empty($customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_CATEGORY])) {
  72. Common::printDebug("WARNING: Overwriting existing Custom Variable in slot " . self::CVAR_INDEX_SEARCH_CATEGORY . " for this page view");
  73. }
  74. $customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_CATEGORY] = self::CVAR_KEY_SEARCH_CATEGORY;
  75. $customVariables['custom_var_v' . self::CVAR_INDEX_SEARCH_CATEGORY] = Request::truncateCustomVariable($this->searchCategory);
  76. }
  77. if ($this->searchCount !== false) {
  78. if (!empty($customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_COUNT])) {
  79. Common::printDebug("WARNING: Overwriting existing Custom Variable in slot " . self::CVAR_INDEX_SEARCH_COUNT . " for this page view");
  80. }
  81. $customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_COUNT] = self::CVAR_KEY_SEARCH_COUNT;
  82. $customVariables['custom_var_v' . self::CVAR_INDEX_SEARCH_COUNT] = (int)$this->searchCount;
  83. }
  84. return $customVariables;
  85. }
  86. protected function detectSiteSearchFromUrl($website, $parsedUrl)
  87. {
  88. $doRemoveSearchParametersFromUrl = true;
  89. $separator = '&';
  90. $count = $actionName = $categoryName = false;
  91. $keywordParameters = isset($website['sitesearch_keyword_parameters'])
  92. ? $website['sitesearch_keyword_parameters']
  93. : array();
  94. $queryString = (!empty($parsedUrl['query']) ? $parsedUrl['query'] : '') . (!empty($parsedUrl['fragment']) ? $separator . $parsedUrl['fragment'] : '');
  95. $parametersRaw = UrlHelper::getArrayFromQueryString($queryString);
  96. // strtolower the parameter names for smooth site search detection
  97. $parameters = array();
  98. foreach ($parametersRaw as $k => $v) {
  99. $parameters[Common::mb_strtolower($k)] = $v;
  100. }
  101. // decode values if they were sent from a client using another charset
  102. $pageEncoding = $this->request->getParam('cs');
  103. PageUrl::reencodeParameters($parameters, $pageEncoding);
  104. // Detect Site Search keyword
  105. foreach ($keywordParameters as $keywordParameterRaw) {
  106. $keywordParameter = Common::mb_strtolower($keywordParameterRaw);
  107. if (!empty($parameters[$keywordParameter])) {
  108. $actionName = $parameters[$keywordParameter];
  109. break;
  110. }
  111. }
  112. if (empty($actionName)) {
  113. return false;
  114. }
  115. $categoryParameters = isset($website['sitesearch_category_parameters'])
  116. ? $website['sitesearch_category_parameters']
  117. : array();
  118. foreach ($categoryParameters as $categoryParameterRaw) {
  119. $categoryParameter = Common::mb_strtolower($categoryParameterRaw);
  120. if (!empty($parameters[$categoryParameter])) {
  121. $categoryName = $parameters[$categoryParameter];
  122. break;
  123. }
  124. }
  125. if (isset($parameters['search_count'])
  126. && $this->isValidSearchCount($parameters['search_count'])
  127. ) {
  128. $count = $parameters['search_count'];
  129. }
  130. // Remove search kwd from URL
  131. if ($doRemoveSearchParametersFromUrl) {
  132. // @see excludeQueryParametersFromUrl()
  133. // Excluded the detected parameters from the URL
  134. $parametersToExclude = array($categoryParameterRaw, $keywordParameterRaw);
  135. if(isset($parsedUrl['query'])) {
  136. $parsedUrl['query'] = UrlHelper::getQueryStringWithExcludedParameters(UrlHelper::getArrayFromQueryString($parsedUrl['query']), $parametersToExclude);
  137. }
  138. if(isset($parsedUrl['fragment'])) {
  139. $parsedUrl['fragment'] = UrlHelper::getQueryStringWithExcludedParameters(UrlHelper::getArrayFromQueryString($parsedUrl['fragment']), $parametersToExclude);
  140. }
  141. }
  142. $url = UrlHelper::getParseUrlReverse($parsedUrl);
  143. if (is_array($actionName)) {
  144. $actionName = reset($actionName);
  145. }
  146. $actionName = trim(urldecode($actionName));
  147. if (empty($actionName)) {
  148. return false;
  149. }
  150. if (is_array($categoryName)) {
  151. $categoryName = reset($categoryName);
  152. }
  153. $categoryName = trim(urldecode($categoryName));
  154. return array($url, $actionName, $categoryName, $count);
  155. }
  156. protected function isValidSearchCount($count)
  157. {
  158. return is_numeric($count) && $count >= 0;
  159. }
  160. protected function detectSiteSearch($originalUrl)
  161. {
  162. $website = Cache::getCacheWebsiteAttributes($this->request->getIdSite());
  163. if (empty($website['sitesearch'])) {
  164. Common::printDebug("Internal 'Site Search' tracking is not enabled for this site. ");
  165. return false;
  166. }
  167. $actionName = $url = $categoryName = $count = false;
  168. $originalUrl = PageUrl::cleanupUrl($originalUrl);
  169. // Detect Site search from Tracking API parameters rather than URL
  170. $searchKwd = $this->request->getParam('search');
  171. if (!empty($searchKwd)) {
  172. $actionName = $searchKwd;
  173. $isCategoryName = $this->request->getParam('search_cat');
  174. if (!empty($isCategoryName)) {
  175. $categoryName = $isCategoryName;
  176. }
  177. $isCount = $this->request->getParam('search_count');
  178. if ($this->isValidSearchCount($isCount)) {
  179. $count = $isCount;
  180. }
  181. }
  182. if (empty($actionName)) {
  183. $parsedUrl = @parse_url($originalUrl);
  184. // Detect Site Search from URL query parameters
  185. if (!empty($parsedUrl['query']) || !empty($parsedUrl['fragment'])) {
  186. // array($url, $actionName, $categoryName, $count);
  187. $searchInfo = $this->detectSiteSearchFromUrl($website, $parsedUrl);
  188. if (!empty($searchInfo)) {
  189. list ($url, $actionName, $categoryName, $count) = $searchInfo;
  190. }
  191. }
  192. }
  193. $actionName = trim($actionName);
  194. $categoryName = trim($categoryName);
  195. if (empty($actionName)) {
  196. Common::printDebug("(this is not a Site Search request)");
  197. return false;
  198. }
  199. Common::printDebug("Detected Site Search keyword '$actionName'. ");
  200. if (!empty($categoryName)) {
  201. Common::printDebug("- Detected Site Search Category '$categoryName'. ");
  202. }
  203. if ($count !== false) {
  204. Common::printDebug("- Search Results Count was '$count'. ");
  205. }
  206. if ($url != $originalUrl) {
  207. Common::printDebug("NOTE: The Page URL was changed / removed, during the Site Search detection, was '$originalUrl', now is '$url'");
  208. }
  209. return array(
  210. $actionName,
  211. $url,
  212. $categoryName,
  213. $count
  214. );
  215. }
  216. }