1 | <?php |
||||
2 | /** |
||||
3 | * Instant Analytics plugin for Craft CMS |
||||
4 | * |
||||
5 | * Instant Analytics brings full Google Analytics support to your Twig templates |
||||
6 | * |
||||
7 | * @link https://nystudio107.com |
||||
0 ignored issues
–
show
Coding Style
introduced
by
![]() |
|||||
8 | * @copyright Copyright (c) 2017 nystudio107 |
||||
0 ignored issues
–
show
|
|||||
9 | */ |
||||
0 ignored issues
–
show
|
|||||
10 | |||||
11 | namespace nystudio107\instantanalytics\services; |
||||
12 | |||||
13 | use Craft; |
||||
14 | use craft\base\Component; |
||||
15 | use craft\elements\User as UserElement; |
||||
16 | use craft\errors\MissingComponentException; |
||||
17 | use craft\helpers\UrlHelper; |
||||
18 | use Jaybizzle\CrawlerDetect\CrawlerDetect; |
||||
19 | use nystudio107\instantanalytics\helpers\IAnalytics; |
||||
20 | use nystudio107\instantanalytics\InstantAnalytics; |
||||
21 | use nystudio107\seomatic\Seomatic; |
||||
0 ignored issues
–
show
The type
nystudio107\seomatic\Seomatic was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||
22 | use yii\base\Exception; |
||||
23 | |||||
24 | /** @noinspection MissingPropertyAnnotationsInspection */ |
||||
0 ignored issues
–
show
|
|||||
25 | |||||
26 | /** |
||||
0 ignored issues
–
show
|
|||||
27 | * @author nystudio107 |
||||
0 ignored issues
–
show
Content of the @author tag must be in the form "Display Name <[email protected]>"
![]() |
|||||
28 | * @package InstantAnalytics |
||||
0 ignored issues
–
show
|
|||||
29 | * @since 1.0.0 |
||||
0 ignored issues
–
show
|
|||||
30 | */ |
||||
0 ignored issues
–
show
|
|||||
31 | class IA extends Component |
||||
32 | { |
||||
33 | // Constants |
||||
34 | // ========================================================================= |
||||
35 | |||||
36 | const DEFAULT_USER_AGENT = "User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13\r\n"; |
||||
37 | |||||
38 | // Public Methods |
||||
39 | // ========================================================================= |
||||
40 | |||||
41 | /** |
||||
0 ignored issues
–
show
|
|||||
42 | * @var null|IAnalytics |
||||
43 | */ |
||||
44 | protected $cachedAnalytics; |
||||
45 | |||||
46 | /** |
||||
47 | * Get the global variables for our Twig context |
||||
48 | * |
||||
49 | * @param $title |
||||
0 ignored issues
–
show
|
|||||
50 | * |
||||
51 | * @return null|IAnalytics |
||||
52 | */ |
||||
53 | public function getGlobals($title) |
||||
54 | { |
||||
55 | if ($this->cachedAnalytics) { |
||||
56 | $analytics = $this->cachedAnalytics; |
||||
57 | } else { |
||||
58 | $analytics = $this->pageViewAnalytics('', $title); |
||||
59 | $this->cachedAnalytics = $analytics; |
||||
60 | } |
||||
61 | |||||
62 | return $analytics; |
||||
63 | } |
||||
64 | |||||
65 | /** |
||||
66 | * Get a PageView analytics object |
||||
67 | * |
||||
68 | * @param string $url |
||||
0 ignored issues
–
show
|
|||||
69 | * @param string $title |
||||
0 ignored issues
–
show
|
|||||
70 | * |
||||
71 | * @return null|IAnalytics |
||||
72 | */ |
||||
73 | public function pageViewAnalytics($url = '', $title = '') |
||||
74 | { |
||||
75 | $result = null; |
||||
76 | $analytics = $this->analytics(); |
||||
77 | if ($analytics) { |
||||
78 | $url = $this->documentPathFromUrl($url); |
||||
79 | // Prepare the Analytics object, and send the pageview |
||||
80 | $analytics->setDocumentPath($url) |
||||
81 | ->setDocumentTitle($title); |
||||
82 | $result = $analytics; |
||||
83 | Craft::info( |
||||
84 | Craft::t( |
||||
85 | 'instant-analytics', |
||||
86 | 'Created sendPageView for: {url} - {title}', |
||||
87 | [ |
||||
88 | 'url' => $url, |
||||
89 | 'title' => $title, |
||||
90 | ] |
||||
91 | ), |
||||
92 | __METHOD__ |
||||
93 | ); |
||||
94 | } |
||||
95 | |||||
96 | return $result; |
||||
97 | } |
||||
98 | |||||
99 | /** |
||||
100 | * Get an Event analytics object |
||||
101 | * |
||||
102 | * @param string $eventCategory |
||||
0 ignored issues
–
show
|
|||||
103 | * @param string $eventAction |
||||
0 ignored issues
–
show
|
|||||
104 | * @param string $eventLabel |
||||
0 ignored issues
–
show
|
|||||
105 | * @param int $eventValue |
||||
0 ignored issues
–
show
|
|||||
106 | * |
||||
107 | * @return null|IAnalytics |
||||
108 | */ |
||||
109 | public function eventAnalytics($eventCategory = '', $eventAction = '', $eventLabel = '', $eventValue = 0) |
||||
110 | { |
||||
111 | $result = null; |
||||
112 | $analytics = $this->analytics(); |
||||
113 | if ($analytics) { |
||||
114 | $url = $this->documentPathFromUrl(); |
||||
115 | $analytics->setDocumentPath($url) |
||||
116 | ->setEventCategory($eventCategory) |
||||
117 | ->setEventAction($eventAction) |
||||
118 | ->setEventLabel($eventLabel) |
||||
119 | ->setEventValue((int)$eventValue); |
||||
120 | $result = $analytics; |
||||
121 | Craft::info( |
||||
122 | Craft::t( |
||||
123 | 'instant-analytics', |
||||
124 | 'Created sendPageView for: {eventCategory} - {eventAction} - {eventLabel} - {eventValue}', |
||||
125 | [ |
||||
126 | 'eventCategory' => $eventCategory, |
||||
127 | 'eventAction' => $eventAction, |
||||
128 | 'eventLabel' => $eventLabel, |
||||
129 | 'eventValue' => $eventValue, |
||||
130 | ] |
||||
131 | ), |
||||
132 | __METHOD__ |
||||
133 | ); |
||||
134 | } |
||||
135 | |||||
136 | return $result; |
||||
137 | } |
||||
138 | |||||
139 | /** |
||||
140 | * getAnalyticsObject() return an analytics object |
||||
0 ignored issues
–
show
|
|||||
141 | * |
||||
142 | * @return null|IAnalytics object |
||||
143 | */ |
||||
144 | public function analytics() |
||||
145 | { |
||||
146 | $analytics = $this->getAnalyticsObj(); |
||||
147 | Craft::info( |
||||
148 | Craft::t( |
||||
149 | 'instant-analytics', |
||||
150 | 'Created generic analytics object' |
||||
151 | ), |
||||
152 | __METHOD__ |
||||
153 | ); |
||||
154 | |||||
155 | return $analytics; |
||||
156 | } |
||||
157 | |||||
158 | /** |
||||
159 | * Get a PageView tracking URL |
||||
160 | * |
||||
161 | * @param $url |
||||
0 ignored issues
–
show
|
|||||
162 | * @param $title |
||||
0 ignored issues
–
show
|
|||||
163 | * |
||||
164 | * @return string |
||||
165 | * @throws \yii\base\Exception |
||||
166 | */ |
||||
167 | public function pageViewTrackingUrl($url, $title): string |
||||
168 | { |
||||
169 | $urlParams = [ |
||||
170 | 'url' => $url, |
||||
171 | 'title' => $title, |
||||
172 | ]; |
||||
173 | $path = parse_url($url, PHP_URL_PATH); |
||||
174 | $pathFragments = explode('/', rtrim($path, '/')); |
||||
175 | $fileName = end($pathFragments); |
||||
176 | $trackingUrl = UrlHelper::siteUrl('instantanalytics/pageViewTrack/' . $fileName, $urlParams); |
||||
177 | Craft::info( |
||||
178 | Craft::t( |
||||
179 | 'instant-analytics', |
||||
180 | 'Created pageViewTrackingUrl for: {trackingUrl}', |
||||
181 | [ |
||||
182 | 'trackingUrl' => $trackingUrl, |
||||
183 | ] |
||||
184 | ), |
||||
185 | __METHOD__ |
||||
186 | ); |
||||
187 | |||||
188 | return $trackingUrl; |
||||
189 | } |
||||
190 | |||||
191 | /** |
||||
192 | * Get an Event tracking URL |
||||
193 | * |
||||
194 | * @param $url |
||||
0 ignored issues
–
show
|
|||||
195 | * @param string $eventCategory |
||||
0 ignored issues
–
show
|
|||||
196 | * @param string $eventAction |
||||
0 ignored issues
–
show
|
|||||
197 | * @param string $eventLabel |
||||
0 ignored issues
–
show
|
|||||
198 | * @param int $eventValue |
||||
0 ignored issues
–
show
|
|||||
199 | * |
||||
200 | * @return string |
||||
201 | * @throws \yii\base\Exception |
||||
202 | */ |
||||
203 | public function eventTrackingUrl( |
||||
204 | $url, |
||||
205 | $eventCategory = '', |
||||
206 | $eventAction = '', |
||||
207 | $eventLabel = '', |
||||
208 | $eventValue = 0 |
||||
209 | ): string |
||||
210 | { |
||||
0 ignored issues
–
show
|
|||||
211 | $urlParams = [ |
||||
212 | 'url' => $url, |
||||
213 | 'eventCategory' => $eventCategory, |
||||
214 | 'eventAction' => $eventAction, |
||||
215 | 'eventLabel' => $eventLabel, |
||||
216 | 'eventValue' => $eventValue, |
||||
217 | ]; |
||||
218 | $fileName = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_BASENAME); |
||||
219 | $trackingUrl = UrlHelper::siteUrl('instantanalytics/eventTrack/' . $fileName, $urlParams); |
||||
0 ignored issues
–
show
Are you sure
$fileName of type array|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
220 | Craft::info( |
||||
221 | Craft::t( |
||||
222 | 'instant-analytics', |
||||
223 | 'Created eventTrackingUrl for: {trackingUrl}', |
||||
224 | [ |
||||
225 | 'trackingUrl' => $trackingUrl, |
||||
226 | ] |
||||
227 | ), |
||||
228 | __METHOD__ |
||||
229 | ); |
||||
230 | |||||
231 | return $trackingUrl; |
||||
232 | } |
||||
233 | |||||
234 | /** |
||||
235 | * _shouldSendAnalytics determines whether we should be sending Google |
||||
236 | * Analytics data |
||||
237 | * |
||||
238 | * @return bool |
||||
239 | */ |
||||
240 | public function shouldSendAnalytics(): bool |
||||
241 | { |
||||
242 | $result = true; |
||||
243 | |||||
244 | $request = Craft::$app->getRequest(); |
||||
245 | |||||
246 | if (!InstantAnalytics::$settings->sendAnalyticsData) { |
||||
247 | $this->logExclusion('sendAnalyticsData'); |
||||
248 | |||||
249 | return false; |
||||
250 | } |
||||
251 | |||||
252 | if (!InstantAnalytics::$settings->sendAnalyticsInDevMode && Craft::$app->getConfig()->getGeneral()->devMode) { |
||||
253 | $this->logExclusion('sendAnalyticsInDevMode'); |
||||
254 | |||||
255 | return false; |
||||
256 | } |
||||
257 | |||||
258 | if ($request->getIsConsoleRequest()) { |
||||
259 | $this->logExclusion('Craft::$app->getRequest()->getIsConsoleRequest()'); |
||||
260 | |||||
261 | return false; |
||||
262 | } |
||||
263 | |||||
264 | if ($request->getIsCpRequest()) { |
||||
265 | $this->logExclusion('Craft::$app->getRequest()->getIsCpRequest()'); |
||||
266 | |||||
267 | return false; |
||||
268 | } |
||||
269 | |||||
270 | if ($request->getIsLivePreview()) { |
||||
271 | $this->logExclusion('Craft::$app->getRequest()->getIsLivePreview()'); |
||||
272 | |||||
273 | return false; |
||||
274 | } |
||||
275 | |||||
276 | // Check the $_SERVER[] super-global exclusions |
||||
277 | if (InstantAnalytics::$settings->serverExcludes !== null |
||||
278 | && \is_array(InstantAnalytics::$settings->serverExcludes)) { |
||||
0 ignored issues
–
show
|
|||||
279 | foreach (InstantAnalytics::$settings->serverExcludes as $match => $matchArray) { |
||||
280 | if (isset($_SERVER[$match])) { |
||||
281 | foreach ($matchArray as $matchItem) { |
||||
282 | if (preg_match($matchItem, $_SERVER[$match])) { |
||||
283 | $this->logExclusion('serverExcludes'); |
||||
284 | |||||
285 | return false; |
||||
286 | } |
||||
287 | } |
||||
288 | } |
||||
289 | } |
||||
290 | } |
||||
291 | |||||
292 | // Filter out bot/spam requests via UserAgent |
||||
293 | if (InstantAnalytics::$settings->filterBotUserAgents) { |
||||
294 | $crawlerDetect = new CrawlerDetect; |
||||
295 | // Check the user agent of the current 'visitor' |
||||
296 | if ($crawlerDetect->isCrawler()) { |
||||
297 | $this->logExclusion('filterBotUserAgents'); |
||||
298 | |||||
299 | return false; |
||||
300 | } |
||||
301 | } |
||||
302 | |||||
303 | // Filter by user group |
||||
304 | $userService = Craft::$app->getUser(); |
||||
305 | /** @var UserElement $user */ |
||||
0 ignored issues
–
show
|
|||||
306 | $user = $userService->getIdentity(); |
||||
307 | if ($user) { |
||||
0 ignored issues
–
show
|
|||||
308 | if (InstantAnalytics::$settings->adminExclude && $user->admin) { |
||||
309 | $this->logExclusion('adminExclude'); |
||||
310 | |||||
311 | return false; |
||||
312 | } |
||||
313 | |||||
314 | if (InstantAnalytics::$settings->groupExcludes !== null |
||||
315 | && \is_array(InstantAnalytics::$settings->groupExcludes)) { |
||||
0 ignored issues
–
show
|
|||||
316 | foreach (InstantAnalytics::$settings->groupExcludes as $matchItem) { |
||||
317 | if ($user->isInGroup($matchItem)) { |
||||
318 | $this->logExclusion('groupExcludes'); |
||||
319 | |||||
320 | return false; |
||||
321 | } |
||||
322 | } |
||||
323 | } |
||||
324 | } |
||||
325 | |||||
326 | return $result; |
||||
327 | } |
||||
328 | |||||
329 | /** |
||||
330 | * Log the reason for excluding the sending of analytics |
||||
331 | * |
||||
332 | * @param string $setting |
||||
0 ignored issues
–
show
|
|||||
333 | */ |
||||
0 ignored issues
–
show
|
|||||
334 | protected function logExclusion(string $setting) |
||||
335 | { |
||||
336 | if (InstantAnalytics::$settings->logExcludedAnalytics) { |
||||
337 | $request = Craft::$app->getRequest(); |
||||
338 | $requestIp = $request->getUserIP(); |
||||
339 | Craft::info( |
||||
340 | Craft::t( |
||||
341 | 'instant-analytics', |
||||
342 | 'Analytics excluded for:: {requestIp} due to: `{setting}`', |
||||
343 | [ |
||||
344 | 'requestIp' => $requestIp, |
||||
345 | 'setting' => $setting, |
||||
346 | ] |
||||
347 | ), |
||||
348 | __METHOD__ |
||||
349 | ); |
||||
350 | } |
||||
351 | } |
||||
352 | |||||
353 | /** |
||||
354 | * Return a sanitized documentPath from a URL |
||||
355 | * |
||||
356 | * @param $url |
||||
0 ignored issues
–
show
|
|||||
357 | * |
||||
358 | * @return string |
||||
359 | */ |
||||
360 | protected function documentPathFromUrl($url = ''): string |
||||
361 | { |
||||
362 | if ($url === '') { |
||||
363 | $url = Craft::$app->getRequest()->getFullPath(); |
||||
364 | } |
||||
365 | |||||
366 | // We want to send just a path to GA for page views |
||||
367 | if (UrlHelper::isAbsoluteUrl($url)) { |
||||
368 | $urlParts = parse_url($url); |
||||
369 | $url = $urlParts['path'] ?? '/'; |
||||
370 | if (isset($urlParts['query'])) { |
||||
371 | $url = $url . '?' . $urlParts['query']; |
||||
372 | } |
||||
373 | } |
||||
374 | |||||
375 | // We don't want to send protocol-relative URLs either |
||||
376 | if (UrlHelper::isProtocolRelativeUrl($url)) { |
||||
377 | $url = substr($url, 1); |
||||
378 | } |
||||
379 | |||||
380 | // Strip the query string if that's the global config setting |
||||
381 | if (InstantAnalytics::$settings) { |
||||
382 | if (InstantAnalytics::$settings->stripQueryString !== null |
||||
383 | && InstantAnalytics::$settings->stripQueryString) { |
||||
0 ignored issues
–
show
|
|||||
384 | $url = UrlHelper::stripQueryString($url); |
||||
385 | } |
||||
386 | } |
||||
387 | |||||
388 | // We always want the path to be / rather than empty |
||||
389 | if ($url === '') { |
||||
390 | $url = '/'; |
||||
391 | } |
||||
392 | |||||
393 | return $url; |
||||
394 | } |
||||
395 | |||||
396 | /** |
||||
397 | * Get the Google Analytics object, primed with the default values |
||||
398 | * |
||||
399 | * @return null|IAnalytics object |
||||
400 | */ |
||||
401 | private function getAnalyticsObj() |
||||
0 ignored issues
–
show
|
|||||
402 | { |
||||
403 | $analytics = null; |
||||
404 | $request = Craft::$app->getRequest(); |
||||
405 | $trackingId = InstantAnalytics::$settings->googleAnalyticsTracking; |
||||
406 | if (InstantAnalytics::$craft31 && !empty($trackingId)) { |
||||
407 | $trackingId = Craft::parseEnv($trackingId); |
||||
0 ignored issues
–
show
The function
Craft::parseEnv() has been deprecated: in 3.7.29. [[App::parseEnv()]] should be used instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||
408 | } |
||||
409 | if (InstantAnalytics::$settings !== null |
||||
410 | && !empty($trackingId)) { |
||||
0 ignored issues
–
show
|
|||||
411 | $analytics = new IAnalytics(); |
||||
412 | if ($analytics) { |
||||
0 ignored issues
–
show
|
|||||
413 | $hostName = $request->getServerName(); |
||||
414 | if (empty($hostName)) { |
||||
415 | try { |
||||
416 | $hostName = parse_url(UrlHelper::siteUrl(), PHP_URL_HOST); |
||||
417 | } catch (Exception $e) { |
||||
418 | Craft::error( |
||||
419 | $e->getMessage(), |
||||
420 | __METHOD__ |
||||
421 | ); |
||||
422 | } |
||||
423 | } |
||||
424 | $userAgent = $request->getUserAgent(); |
||||
425 | if ($userAgent === null) { |
||||
426 | $userAgent = self::DEFAULT_USER_AGENT; |
||||
427 | } |
||||
428 | $referrer = $request->getReferrer(); |
||||
429 | if ($referrer === null) { |
||||
430 | $referrer = ''; |
||||
431 | } |
||||
432 | $analytics->setProtocolVersion('1') |
||||
433 | ->setTrackingId($trackingId) |
||||
434 | ->setIpOverride($request->getUserIP()) |
||||
435 | ->setUserAgentOverride($userAgent) |
||||
436 | ->setDocumentHostName($hostName) |
||||
437 | ->setDocumentReferrer($referrer) |
||||
438 | ->setAsyncRequest(false); |
||||
439 | |||||
440 | // Try to parse a clientId from an existing _ga cookie |
||||
441 | $clientId = $this->gaParseCookie(); |
||||
442 | if (!empty($clientId)) { |
||||
443 | $analytics->setClientId($clientId); |
||||
444 | } |
||||
445 | // Set the gclid |
||||
446 | $gclid = $this->getGclid(); |
||||
447 | if ($gclid) { |
||||
448 | $analytics->setGoogleAdwordsId($gclid); |
||||
449 | } |
||||
450 | |||||
451 | // Handle UTM parameters |
||||
452 | try { |
||||
453 | $session = Craft::$app->getSession(); |
||||
454 | } catch (MissingComponentException $e) { |
||||
455 | // That's ok |
||||
456 | $session = null; |
||||
457 | } |
||||
458 | // utm_source |
||||
459 | $utm_source = $request->getParam('utm_source') ?? $session->get('utm_source') ?? null; |
||||
460 | if (!empty($utm_source)) { |
||||
461 | $analytics->setCampaignSource($utm_source); |
||||
462 | if ($session) { |
||||
463 | $session->set('utm_source', $utm_source); |
||||
464 | } |
||||
465 | } |
||||
466 | // utm_medium |
||||
467 | $utm_medium = $request->getParam('utm_medium') ?? $session->get('utm_medium') ?? null; |
||||
468 | if (!empty($utm_medium)) { |
||||
469 | $analytics->setCampaignMedium($utm_medium); |
||||
470 | if ($session) { |
||||
471 | $session->set('utm_medium', $utm_medium); |
||||
472 | } |
||||
473 | } |
||||
474 | // utm_campaign |
||||
475 | $utm_campaign = $request->getParam('utm_campaign') ?? $session->get('utm_campaign') ?? null; |
||||
476 | if (!empty($utm_campaign)) { |
||||
477 | $analytics->setCampaignName($utm_campaign); |
||||
478 | if ($session) { |
||||
479 | $session->set('utm_campaign', $utm_campaign); |
||||
480 | } |
||||
481 | } |
||||
482 | // utm_content |
||||
483 | $utm_content = $request->getParam('utm_content') ?? $session->get('utm_content') ?? null; |
||||
484 | if (!empty($utm_content)) { |
||||
485 | $analytics->setCampaignContent($utm_content); |
||||
486 | if ($session) { |
||||
487 | $session->set('utm_content', $utm_content); |
||||
488 | } |
||||
489 | } |
||||
490 | |||||
491 | // If SEOmatic is installed, set the affiliation as well |
||||
492 | if (InstantAnalytics::$seomaticPlugin && Seomatic::$settings->renderEnabled |
||||
493 | && Seomatic::$plugin->metaContainers->metaSiteVars !== null) { |
||||
0 ignored issues
–
show
|
|||||
494 | $siteName = Seomatic::$plugin->metaContainers->metaSiteVars->siteName; |
||||
495 | $analytics->setAffiliation($siteName); |
||||
496 | } |
||||
497 | } |
||||
498 | } |
||||
499 | |||||
500 | return $analytics; |
||||
501 | } /* -- _getAnalyticsObj */ |
||||
502 | |||||
503 | /** |
||||
504 | * _getGclid get the `gclid` and sets the 'gclid' cookie |
||||
505 | */ |
||||
506 | /** |
||||
507 | * _getGclid get the `gclid` and sets the 'gclid' cookie |
||||
508 | * |
||||
509 | * @return string |
||||
510 | */ |
||||
511 | private function getGclid(): string |
||||
0 ignored issues
–
show
|
|||||
512 | { |
||||
513 | $gclid = ''; |
||||
514 | if (isset($_GET['gclid'])) { |
||||
515 | $gclid = $_GET['gclid']; |
||||
516 | if (InstantAnalytics::$settings->createGclidCookie && !empty($gclid)) { |
||||
517 | setcookie('gclid', $gclid, strtotime('+10 years'), '/'); |
||||
518 | } |
||||
519 | } |
||||
520 | |||||
521 | return $gclid; |
||||
522 | } |
||||
523 | |||||
524 | /** |
||||
525 | * gaParseCookie handles the parsing of the _ga cookie or setting it to a |
||||
0 ignored issues
–
show
|
|||||
526 | * unique identifier |
||||
527 | * |
||||
528 | * @return string the cid |
||||
529 | */ |
||||
530 | private function gaParseCookie(): string |
||||
0 ignored issues
–
show
|
|||||
531 | { |
||||
532 | $cid = ''; |
||||
533 | if (isset($_COOKIE['_ga'])) { |
||||
534 | $parts = preg_split('[\.]', $_COOKIE['_ga'], 4); |
||||
535 | if ($parts !== false) { |
||||
536 | $cid = implode('.', \array_slice($parts, 2)); |
||||
537 | } |
||||
538 | } elseif (isset($_COOKIE['_ia']) && $_COOKIE['_ia'] !== '') { |
||||
539 | $cid = $_COOKIE['_ia']; |
||||
540 | } else { |
||||
541 | // Only generate our own unique clientId if `requireGaCookieClientId` isn't true |
||||
542 | if (!InstantAnalytics::$settings->requireGaCookieClientId) { |
||||
543 | $cid = $this->gaGenUUID(); |
||||
544 | } |
||||
545 | } |
||||
546 | if (InstantAnalytics::$settings->createGclidCookie && !empty($cid)) { |
||||
547 | setcookie('_ia', $cid, strtotime('+2 years'), '/'); // Two years |
||||
548 | } |
||||
549 | |||||
550 | return $cid; |
||||
551 | } |
||||
552 | |||||
553 | /** |
||||
554 | * gaGenUUID Generate UUID v4 function - needed to generate a CID when one |
||||
0 ignored issues
–
show
|
|||||
555 | * isn't available |
||||
556 | * |
||||
557 | * @return string The generated UUID |
||||
558 | */ |
||||
559 | private function gaGenUUID() |
||||
0 ignored issues
–
show
|
|||||
560 | { |
||||
561 | return sprintf( |
||||
562 | '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', |
||||
563 | // 32 bits for "time_low" |
||||
564 | mt_rand(0, 0xffff), |
||||
565 | mt_rand(0, 0xffff), |
||||
566 | // 16 bits for "time_mid" |
||||
567 | mt_rand(0, 0xffff), |
||||
568 | // 16 bits for "time_hi_and_version", |
||||
569 | // four most significant bits holds version number 4 |
||||
570 | mt_rand(0, 0x0fff) | 0x4000, |
||||
571 | // 16 bits, 8 bits for "clk_seq_hi_res", |
||||
572 | // 8 bits for "clk_seq_low", |
||||
573 | // two most significant bits holds zero and one for variant DCE1.1 |
||||
574 | mt_rand(0, 0x3fff) | 0x8000, |
||||
575 | // 48 bits for "node" |
||||
576 | mt_rand(0, 0xffff), |
||||
577 | mt_rand(0, 0xffff), |
||||
578 | mt_rand(0, 0xffff) |
||||
579 | ); |
||||
580 | } |
||||
581 | } |
||||
582 |