PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.0.5
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.0.5
5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Tracker / PageUrl.php
matomo / app / core / Tracker Last commit date
Db 6 years ago Handler 6 years ago TableLogAction 6 years ago Visit 6 years ago Action.php 6 years ago ActionPageview.php 6 years ago Cache.php 6 years ago Db.php 6 years ago Failures.php 6 years ago GoalManager.php 6 years ago Handler.php 6 years ago IgnoreCookie.php 6 years ago LogTable.php 6 years ago Model.php 6 years ago PageUrl.php 6 years ago Request.php 6 years ago RequestProcessor.php 6 years ago RequestSet.php 6 years ago Response.php 6 years ago ScheduledTasksRunner.php 6 years ago Settings.php 6 years ago TableLogAction.php 6 years ago TrackerCodeGenerator.php 6 years ago TrackerConfig.php 6 years ago Visit.php 6 years ago VisitExcluded.php 6 years ago VisitInterface.php 6 years ago Visitor.php 6 years ago VisitorNotFoundInDb.php 6 years ago VisitorRecognizer.php 6 years ago
PageUrl.php
386 lines
1 <?php
2 /**
3 * Piwik - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9
10 namespace Piwik\Tracker;
11
12 use Piwik\Common;
13 use Piwik\Config;
14 use Piwik\Piwik;
15 use Piwik\UrlHelper;
16
17 class PageUrl
18 {
19
20 /**
21 * Map URL prefixes to integers.
22 * @see self::normalizeUrl(), self::reconstructNormalizedUrl()
23 */
24 public static $urlPrefixMap = array(
25 'http://www.' => 1,
26 'http://' => 0,
27 'https://www.' => 3,
28 'https://' => 2
29 );
30
31 /**
32 * Given the Input URL, will exclude all query parameters set for this site
33 *
34 * @static
35 * @param $originalUrl
36 * @param $idSite
37 * @return bool|string Returned URL is HTML entities decoded
38 */
39 public static function excludeQueryParametersFromUrl($originalUrl, $idSite)
40 {
41 $originalUrl = self::cleanupUrl($originalUrl);
42
43 $parsedUrl = @parse_url($originalUrl);
44 $parsedUrl = self::cleanupHostAndHashTag($parsedUrl, $idSite);
45 $parametersToExclude = self::getQueryParametersToExclude($idSite);
46
47 if (empty($parsedUrl['query'])) {
48 if (empty($parsedUrl['fragment'])) {
49 return UrlHelper::getParseUrlReverse($parsedUrl);
50 }
51
52 // Exclude from the hash tag as well
53 $queryParameters = UrlHelper::getArrayFromQueryString($parsedUrl['fragment']);
54 $parsedUrl['fragment'] = UrlHelper::getQueryStringWithExcludedParameters($queryParameters, $parametersToExclude);
55 $url = UrlHelper::getParseUrlReverse($parsedUrl);
56
57 return $url;
58 }
59
60 $queryParameters = UrlHelper::getArrayFromQueryString($parsedUrl['query']);
61 $parsedUrl['query'] = UrlHelper::getQueryStringWithExcludedParameters($queryParameters, $parametersToExclude);
62 $url = UrlHelper::getParseUrlReverse($parsedUrl);
63
64 return $url;
65 }
66
67 /**
68 * Returns the array of parameters names that must be excluded from the Query String in all tracked URLs
69 * @static
70 * @param $idSite
71 * @return array
72 */
73 public static function getQueryParametersToExclude($idSite)
74 {
75 $campaignTrackingParameters = Common::getCampaignParameters();
76
77 $campaignTrackingParameters = array_merge(
78 $campaignTrackingParameters[0], // campaign name parameters
79 $campaignTrackingParameters[1] // campaign keyword parameters
80 );
81
82 $website = Cache::getCacheWebsiteAttributes($idSite);
83 $excludedParameters = self::getExcludedParametersFromWebsite($website);
84
85 $parametersToExclude = array_merge($excludedParameters,
86 self::getUrlParameterNamesToExcludeFromUrl(),
87 $campaignTrackingParameters);
88
89 /**
90 * Triggered before setting the action url in Piwik\Tracker\Action so plugins can register
91 * parameters to be excluded from the tracking URL (e.g. campaign parameters).
92 *
93 * @param array &$parametersToExclude An array of parameters to exclude from the tracking url.
94 */
95 Piwik::postEvent('Tracker.PageUrl.getQueryParametersToExclude', array(&$parametersToExclude));
96
97 if (!empty($parametersToExclude)) {
98 Common::printDebug('Excluding parameters "' . implode(',', $parametersToExclude) . '" from URL');
99 }
100
101 $parametersToExclude = array_map('strtolower', $parametersToExclude);
102 return $parametersToExclude;
103 }
104
105 /**
106 * Returns the list of URL query parameters that should be removed from the tracked URL query string.
107 *
108 * @return array
109 */
110 protected static function getUrlParameterNamesToExcludeFromUrl()
111 {
112 $paramsToExclude = Config::getInstance()->Tracker['url_query_parameter_to_exclude_from_url'];
113 $paramsToExclude = explode(",", $paramsToExclude);
114 $paramsToExclude = array_map('trim', $paramsToExclude);
115 return $paramsToExclude;
116 }
117
118 /**
119 * Returns true if URL fragments should be removed for a specific site,
120 * false if otherwise.
121 *
122 * This function uses the Tracker cache and not the MySQL database.
123 *
124 * @param $idSite int The ID of the site to check for.
125 * @return bool
126 */
127 public static function shouldRemoveURLFragmentFor($idSite)
128 {
129 $websiteAttributes = Cache::getCacheWebsiteAttributes($idSite);
130 return empty($websiteAttributes['keep_url_fragment']);
131 }
132
133 /**
134 * Cleans and/or removes the URL fragment of a URL.
135 *
136 * @param $urlFragment string The URL fragment to process.
137 * @param $idSite int|bool If not false, this function will check if URL fragments
138 * should be removed for the site w/ this ID and if so,
139 * the returned processed fragment will be empty.
140 *
141 * @return string The processed URL fragment.
142 */
143 public static function processUrlFragment($urlFragment, $idSite = false)
144 {
145 // if we should discard the url fragment for this site, return an empty string as
146 // the processed url fragment
147 if ($idSite !== false
148 && PageUrl::shouldRemoveURLFragmentFor($idSite)
149 ) {
150 return '';
151 } else {
152 // Remove trailing Hash tag in ?query#hash#
153 if (substr($urlFragment, -1) == '#') {
154 $urlFragment = substr($urlFragment, 0, strlen($urlFragment) - 1);
155 }
156 return $urlFragment;
157 }
158 }
159
160 /**
161 * Will cleanup the hostname (some browser do not strolower the hostname),
162 * and deal ith the hash tag on incoming URLs based on website setting.
163 *
164 * @param $parsedUrl
165 * @param $idSite int|bool The site ID of the current visit. This parameter is
166 * only used by the tracker to see if we should remove
167 * the URL fragment for this site.
168 * @return array
169 */
170 protected static function cleanupHostAndHashTag($parsedUrl, $idSite = false)
171 {
172 if (empty($parsedUrl)) {
173 return $parsedUrl;
174 }
175
176 if (!empty($parsedUrl['host'])) {
177 $parsedUrl['host'] = Common::mb_strtolower($parsedUrl['host']);
178 }
179
180 if (!empty($parsedUrl['fragment'])) {
181 $parsedUrl['fragment'] = PageUrl::processUrlFragment($parsedUrl['fragment'], $idSite);
182 }
183
184 return $parsedUrl;
185 }
186
187 /**
188 * Converts Matrix URL format
189 * from http://example.org/thing;paramA=1;paramB=6542
190 * to http://example.org/thing?paramA=1&paramB=6542
191 *
192 * @param string $originalUrl
193 * @return string
194 */
195 public static function convertMatrixUrl($originalUrl)
196 {
197 $posFirstSemiColon = strpos($originalUrl, ";");
198
199 if (false === $posFirstSemiColon) {
200 return $originalUrl;
201 }
202
203 $posQuestionMark = strpos($originalUrl, "?");
204 $replace = (false === $posQuestionMark);
205
206 if ($posQuestionMark > $posFirstSemiColon) {
207 $originalUrl = substr_replace($originalUrl, ";", $posQuestionMark, 1);
208 $replace = true;
209 }
210
211 if ($replace) {
212 $originalUrl = substr_replace($originalUrl, "?", strpos($originalUrl, ";"), 1);
213 $originalUrl = str_replace(";", "&", $originalUrl);
214 }
215
216 return $originalUrl;
217 }
218
219 /**
220 * Clean up string contents (filter, truncate, ...)
221 *
222 * @param string $string Dirty string
223 * @return string
224 */
225 public static function cleanupString($string)
226 {
227 $string = trim($string);
228 $string = str_replace(array("\n", "\r", "\0"), '', $string);
229
230 $limit = Config::getInstance()->Tracker['page_maximum_length'];
231 $clean = substr($string, 0, $limit);
232 return $clean;
233 }
234
235 protected static function reencodeParameterValue($value, $encoding)
236 {
237 if (is_string($value)) {
238 $decoded = urldecode($value);
239 if (function_exists('mb_check_encoding')
240 && @mb_check_encoding($decoded, $encoding)) {
241 $value = urlencode(mb_convert_encoding($decoded, 'UTF-8', $encoding));
242 }
243 }
244
245 return $value;
246 }
247
248 protected static function reencodeParametersArray($queryParameters, $encoding)
249 {
250 foreach ($queryParameters as &$value) {
251 if (is_array($value)) {
252 $value = self::reencodeParametersArray($value, $encoding);
253 } else {
254 $value = PageUrl::reencodeParameterValue($value, $encoding);
255 }
256 }
257
258 return $queryParameters;
259 }
260
261 /**
262 * Checks if query parameters are of a non-UTF-8 encoding and converts the values
263 * from the specified encoding to UTF-8.
264 * This method is used to workaround browser/webapp bugs (see #3450). When
265 * browsers fail to encode query parameters in UTF-8, the tracker will send the
266 * charset of the page viewed and we can sometimes work around invalid data
267 * being stored.
268 *
269 * @param array $queryParameters Name/value mapping of query parameters.
270 * @param bool|string $encoding of the HTML page the URL is for. Used to workaround
271 * browser bugs & mis-coded webapps. See #3450.
272 *
273 * @return array
274 */
275 public static function reencodeParameters(&$queryParameters, $encoding = false)
276 {
277 if (function_exists('mb_check_encoding')) {
278 // if query params are encoded w/ non-utf8 characters (due to browser bug or whatever),
279 // encode to UTF-8.
280 if (strtolower($encoding) != 'utf-8'
281 && $encoding != false
282 ) {
283 Common::printDebug("Encoding page URL query parameters to $encoding.");
284
285 $queryParameters = PageUrl::reencodeParametersArray($queryParameters, $encoding);
286 }
287 } else {
288 Common::printDebug("Page charset supplied in tracking request, but mbstring extension is not available.");
289 }
290
291 return $queryParameters;
292 }
293
294 public static function cleanupUrl($url)
295 {
296 $url = Common::unsanitizeInputValue($url);
297 $url = PageUrl::cleanupString($url);
298 $url = PageUrl::convertMatrixUrl($url);
299
300 return $url;
301 }
302
303 /**
304 * Build the full URL from the prefix ID and the rest.
305 *
306 * @param string $url
307 * @param integer $prefixId
308 * @return string
309 */
310 public static function reconstructNormalizedUrl($url, $prefixId)
311 {
312 $map = array_flip(self::$urlPrefixMap);
313
314 if ($prefixId !== null && isset($map[$prefixId])) {
315 $fullUrl = $map[$prefixId] . $url;
316 } else {
317 $fullUrl = $url;
318 }
319
320 // Clean up host & hash tags, for URLs
321 $parsedUrl = @parse_url($fullUrl);
322 $parsedUrl = PageUrl::cleanupHostAndHashTag($parsedUrl);
323 $url = UrlHelper::getParseUrlReverse($parsedUrl);
324
325 if (!empty($url)) {
326 return $url;
327 }
328
329 return $fullUrl;
330 }
331
332 /**
333 * Extract the prefix from a URL.
334 * Return the prefix ID and the rest.
335 *
336 * @param string $url
337 * @return array
338 */
339 public static function normalizeUrl($url)
340 {
341 foreach (self::$urlPrefixMap as $prefix => $id) {
342 if (strtolower(substr($url, 0, strlen($prefix))) == $prefix) {
343 return array(
344 'url' => substr($url, strlen($prefix)),
345 'prefixId' => $id
346 );
347 }
348 }
349
350 return array('url' => $url, 'prefixId' => null);
351 }
352
353 public static function getUrlIfLookValid($url)
354 {
355 $url = PageUrl::cleanupString($url);
356
357 if (!UrlHelper::isLookLikeUrl($url)) {
358 Common::printDebug("WARNING: URL looks invalid and is discarded");
359
360 return false;
361 }
362
363 return $url;
364 }
365
366 private static function getExcludedParametersFromWebsite($website)
367 {
368 if (isset($website['excluded_parameters'])) {
369 return $website['excluded_parameters'];
370 }
371
372 return array();
373 }
374
375 public static function urldecodeValidUtf8($value)
376 {
377 $value = urldecode($value);
378 if (function_exists('mb_check_encoding')
379 && !@mb_check_encoding($value, 'utf-8')
380 ) {
381 return urlencode($value);
382 }
383 return $value;
384 }
385 }
386