IA   F
last analyzed

Complexity

Total Complexity 79

Size/Duplication

Total Lines 548
Duplicated Lines 0 %

Importance

Changes 13
Bugs 0 Features 0
Metric Value
wmc 79
eloc 243
c 13
b 0
f 0
dl 0
loc 548
rs 2.08

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getGlobals() 0 10 2
A pageViewAnalytics() 0 24 2
A getGclid() 0 11 4
A eventAnalytics() 0 28 2
A gaGenUUID() 0 20 1
A logExclusion() 0 15 2
A pageViewTrackingUrl() 0 22 1
B gaParseCookie() 0 21 8
B documentPathFromUrl() 0 34 9
F getAnalyticsObj() 0 100 24
A eventTrackingUrl() 0 29 1
D shouldSendAnalytics() 0 87 22
A analytics() 0 12 1

How to fix   Complexity   

Complex Class

Complex classes like IA often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use IA, and based on these observations, apply Extract Interface, too.

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
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2017 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
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
Bug introduced by
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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use yii\base\Exception;
23
24
/** @noinspection MissingPropertyAnnotationsInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
25
26
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
27
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
28
 * @package   InstantAnalytics
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
29
 * @since     1.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
30
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
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
Coding Style introduced by
Missing short description in doc comment
Loading history...
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
Coding Style introduced by
Missing parameter comment
Loading history...
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
Coding Style introduced by
Missing parameter comment
Loading history...
69
     * @param string $title
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
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
Coding Style introduced by
Missing parameter comment
Loading history...
103
     * @param string $eventAction
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
104
     * @param string $eventLabel
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
105
     * @param int $eventValue
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
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
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
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
Coding Style introduced by
Missing parameter comment
Loading history...
162
     * @param $title
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
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
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 1 spaces but found 8
Loading history...
195
     * @param string $eventCategory
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
196
     * @param string $eventAction
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
197
     * @param string $eventLabel
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
198
     * @param int $eventValue
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
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
Coding Style introduced by
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
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
Bug introduced by
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 ignore-type  annotation

219
        $trackingUrl = UrlHelper::siteUrl('instantanalytics/eventTrack/' . /** @scrutinizer ignore-type */ $fileName, $urlParams);
Loading history...
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
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
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
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
306
        $user = $userService->getIdentity();
307
        if ($user) {
0 ignored issues
show
introduced by
$user is of type craft\elements\User, thus it always evaluated to true.
Loading history...
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
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
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
Coding Style introduced by
Missing parameter comment
Loading history...
333
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
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
Coding Style introduced by
Missing parameter comment
Loading history...
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
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
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
Coding Style introduced by
Private method name "IA::getAnalyticsObj" must be prefixed with an underscore
Loading history...
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
Deprecated Code introduced by
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 ignore-deprecated  annotation

407
            $trackingId = /** @scrutinizer ignore-deprecated */ Craft::parseEnv($trackingId);

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.

Loading history...
408
        }
409
        if (InstantAnalytics::$settings !== null
410
            && !empty($trackingId)) {
0 ignored issues
show
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
411
            $analytics = new IAnalytics();
412
            if ($analytics) {
0 ignored issues
show
introduced by
$analytics is of type nystudio107\instantanalytics\helpers\IAnalytics, thus it always evaluated to true.
Loading history...
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
Coding Style introduced by
Closing parenthesis of a multi-line IF statement must be on a new line
Loading history...
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
Coding Style introduced by
Private method name "IA::getGclid" must be prefixed with an underscore
Loading history...
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
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
526
     * unique identifier
527
     *
528
     * @return string the cid
529
     */
530
    private function gaParseCookie(): string
0 ignored issues
show
Coding Style introduced by
Private method name "IA::gaParseCookie" must be prefixed with an underscore
Loading history...
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
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
555
     * isn't available
556
     *
557
     * @return string The generated UUID
558
     */
559
    private function gaGenUUID()
0 ignored issues
show
Coding Style introduced by
Private method name "IA::gaGenUUID" must be prefixed with an underscore
Loading history...
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