tag is added to the webpage with a Matomo URL as the source, this URL serves the opt-out * content and sets the opt-out cookie for the Matomo URL domain. Translation and styling is done * server side, a third party cookie is set. Not well supported with modern browser third party cookie * restrictions, no longer offered as an option in the UI but the content URL is supported for existing * webpages still using the iFrame code. * * JavaScript : an empty
'+settings.YouMayOptOut2+' '+settings.YouMayOptOut3+'
'; } if (useTracker) { content += ''; } else { content += ''; } content += ''; } else { if (settings.showIntro) { content += ''+settings.OptOutComplete+' '+settings.OptOutCompleteBis+'
'; } if (useTracker) { content += ''; } else { content += ''; } content += ''; } div.innerHTML = content; }; window.MatomoConsent = { cookiesDisabled: (!navigator || !navigator.cookieEnabled), CONSENT_COOKIE_NAME: 'mtm_consent', CONSENT_REMOVED_COOKIE_NAME: 'mtm_consent_removed', cookieIsSecure: false, useSecureCookies: true, cookiePath: '', cookieDomain: '', cookieSameSite: 'Lax', init: function(useSecureCookies, cookiePath, cookieDomain, cookieSameSite) { this.useSecureCookies = useSecureCookies; this.cookiePath = cookiePath; this.cookieDomain = cookieDomain; this.cookieSameSite = cookieSameSite; if(useSecureCookies && location.protocol !== 'https:') { console.log('Error with setting useSecureCookies: You cannot use this option on http.'); } else { this.cookieIsSecure = useSecureCookies; } }, hasConsent: function() { var value = this.getCookie(this.CONSENT_COOKIE_NAME); if (this.getCookie(this.CONSENT_REMOVED_COOKIE_NAME) && value) { this.setCookie(this.CONSENT_COOKIE_NAME, '', -129600000); return false; } return (value || value !== 0); }, consentGiven: function() { this.setCookie(this.CONSENT_REMOVED_COOKIE_NAME, '', -129600000); this.setCookie(this.CONSENT_COOKIE_NAME, new Date().getTime(), 946080000000); }, consentRevoked: function() { this.setCookie(this.CONSENT_COOKIE_NAME, '', -129600000); this.setCookie(this.CONSENT_REMOVED_COOKIE_NAME, new Date().getTime(), 946080000000); }, getCookie: function(cookieName) { var cookiePattern = new RegExp('(^|;)[ ]*' + cookieName + '=([^;]*)'), cookieMatch = cookiePattern.exec(document.cookie); return cookieMatch ? window.decodeURIComponent(cookieMatch[2]) : 0; }, setCookie: function(cookieName, value, msToExpire) { var expiryDate = new Date(); expiryDate.setTime((new Date().getTime()) + msToExpire); document.cookie = cookieName + '=' + window.encodeURIComponent(value) + (msToExpire ? ';expires=' + expiryDate.toGMTString() : '') + ';path=' + (this.cookiePath || '/') + (this.cookieDomain ? ';domain=' + this.cookieDomain : '') + (this.cookieIsSecure ? ';secure' : '') + ';SameSite=' + this.cookieSameSite; if ((!msToExpire || msToExpire >= 0) && this.getCookie(cookieName) !== String(value)) { console.log('There was an error setting cookie `' + cookieName + '`. Please check domain and path.'); } } }; JS; } /** * Get translations used by the opt-out popup * * @param string|null $language * * @return array */ private function getTranslations(string $language = null) : array { return [ 'OptOutComplete' => Piwik::translate('CoreAdminHome_OptOutComplete', [], $language), 'OptOutCompleteBis' => Piwik::translate('CoreAdminHome_OptOutCompleteBis', [], $language), 'YouMayOptOut2' => Piwik::translate('CoreAdminHome_YouMayOptOut2', [], $language), 'YouMayOptOut3' => Piwik::translate('CoreAdminHome_YouMayOptOut3', [], $language), 'OptOutErrorNoCookies' => Piwik::translate('CoreAdminHome_OptOutErrorNoCookies', [], $language), 'OptOutErrorNotHttps' => Piwik::translate('CoreAdminHome_OptOutErrorNotHttps', [], $language), 'YouAreNotOptedOut' => Piwik::translate('CoreAdminHome_YouAreNotOptedOut', [], $language), 'UncheckToOptOut' => Piwik::translate('CoreAdminHome_UncheckToOptOut', [], $language), 'YouAreOptedOut' => Piwik::translate('CoreAdminHome_YouAreOptedOut', [], $language), 'CheckToOptIn' => Piwik::translate('CoreAdminHome_CheckToOptIn', [], $language), ]; } /** * Return the content of the iFrame opt out * * @return View * @throws \Exception */ public function getOptOutViewIFrame() { if ($this->view) { return $this->view; } $trackVisits = !IgnoreCookie::isIgnoreCookieFound(); $dntFound = $this->getDoNotTrackHeaderChecker()->isDoNotTrackFound(); $setCookieInNewWindow = Common::getRequestVar('setCookieInNewWindow', false, 'int'); if ($setCookieInNewWindow) { $nonce = Common::getRequestVar('nonce', false); if ($nonce !== false && !Nonce::verifyNonce('Piwik_OptOut', $nonce)) { Nonce::discardNonce('Piwik_OptOut'); $nonce = ''; } $reloadUrl = Url::getCurrentQueryStringWithParametersModified(array( 'showConfirmOnly' => 1, 'setCookieInNewWindow' => 0, 'nonce' => $nonce ? : '' )); } else { $reloadUrl = false; $requestNonce = Common::getRequestVar('nonce', false); if ($requestNonce !== false && Nonce::verifyNonce('Piwik_OptOut', $requestNonce)) { Nonce::discardNonce('Piwik_OptOut'); IgnoreCookie::setIgnoreCookie(); $trackVisits = !$trackVisits; } } $language = Common::getRequestVar('language', ''); $lang = APILanguagesManager::getInstance()->isLanguageAvailable($language) ? $language : LanguagesManager::getLanguageCodeForCurrentUser(); $nonce = Nonce::getNonce('Piwik_OptOut', 3600); $this->addQueryParameters(array( 'module' => 'CoreAdminHome', 'action' => 'optOut', 'language' => $lang, 'setCookieInNewWindow' => 1, 'nonce' => $nonce ), false); if (Common::getRequestVar('applyStyling', 1, 'int')) { $this->addStylesheet($this->optOutStyling()); } $this->view = new View("@CoreAdminHome/optOut"); $this->addJavaScript('plugins/CoreAdminHome/javascripts/optOut.js', false); $this->view->setXFrameOptions('allow'); $this->view->dntFound = $dntFound; $this->view->trackVisits = $trackVisits; $this->view->nonce = $nonce; $this->view->language = $lang; $this->view->showIntro = Common::getRequestVar('showIntro', 1, 'int'); $this->view->showConfirmOnly = Common::getRequestVar('showConfirmOnly', false, 'int'); $this->view->reloadUrl = $reloadUrl; $this->view->javascripts = $this->getJavaScripts(); $this->view->stylesheets = $this->getStylesheets(); $this->view->title = $this->getTitle(); $this->view->queryParameters = $this->getQueryParameters(); return $this->view; } /** * Provide a CSS style sheet based on the chosen opt out style options * * @param string|null $fontSize * @param string|null $fontColor * @param string|null $fontFamily * @param string|null $backgroundColor * @param bool $noBody * * @return string * @throws \Exception */ private function optOutStyling(?string $fontSize = null, ?string $fontColor = null, ?string $fontFamily = null, ?string $backgroundColor = null, bool $noBody = false): string { $cssfontsize = ($fontSize ? : Common::unsanitizeInputValue(Common::getRequestVar('fontSize', false, 'string'))); $cssfontcolour = ($fontColor ? : Common::unsanitizeInputValue(Common::getRequestVar('fontColor', false, 'string'))); $cssfontfamily = ($fontFamily ? : Common::unsanitizeInputValue(Common::getRequestVar('fontFamily', false, 'string'))); $cssbackgroundcolor = ($backgroundColor ? : Common::unsanitizeInputValue(Common::getRequestVar('backgroundColor', false, 'string'))); if (!$noBody) { $cssbody = 'body { '; } else { $cssbody = ''; } $hexstrings = array( 'fontColor' => $cssfontcolour, 'backgroundColor' => $cssbackgroundcolor ); foreach ($hexstrings as $key => $testcase) { if ($testcase && !(ctype_xdigit($testcase) && in_array(strlen($testcase),array(3,6), true))) { throw new \Exception("The URL parameter $key value of '$testcase' is not valid. Expected value is for example 'ffffff' or 'fff'.\n"); } } /** @noinspection RegExpRedundantEscape */ if ($cssfontsize && (preg_match("/^[0-9]+[\.]?[0-9]*(px|pt|em|rem|%)$/", $cssfontsize))) { $cssbody .= 'font-size: ' . $cssfontsize . '; '; } else if ($cssfontsize) { throw new \Exception("The URL parameter fontSize value of '$cssfontsize' is not valid. Expected value is for example '15pt', '1.2em' or '13px'.\n"); } /** @noinspection RegExpRedundantEscape */ if ($cssfontfamily && (preg_match('/^[a-zA-Z0-9-\ ,\'"]+$/', $cssfontfamily))) { $cssbody .= 'font-family: ' . $cssfontfamily . '; '; } else if ($cssfontfamily) { throw new \Exception("The URL parameter fontFamily value of '$cssfontfamily' is not valid. Expected value is for example 'sans-serif' or 'Monaco, monospace'.\n"); } if ($cssfontcolour) { $cssbody .= 'color: #' . $cssfontcolour . '; '; } if ($cssbackgroundcolor) { $cssbody .= 'background-color: #' . $cssbackgroundcolor . '; '; } if (!$noBody) { $cssbody .= '}'; } return $cssbody; } /** * @return DoNotTrackHeaderChecker */ protected function getDoNotTrackHeaderChecker() { return $this->doNotTrackHeaderChecker; } }