147 lines
5.7 KiB
PHP
147 lines
5.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/bootstrap.php';
|
|
|
|
const APP_ANALYTICS_CONSENT_COOKIE = 'kaffeeliste_analytics_consent';
|
|
const APP_ANALYTICS_CONSENT_VERSION = '1';
|
|
const APP_ANALYTICS_CONSENT_MAX_AGE = 15552000; // 180 Tage
|
|
|
|
/**
|
|
* @return list<string>
|
|
*/
|
|
function app_matomo_configuration_errors(): array
|
|
{
|
|
$url = trim((string)app_env('MATOMO_URL', ''));
|
|
$siteId = trim((string)app_env('MATOMO_SITE_ID', ''));
|
|
$privacyConfirmed = trim((string)app_env('MATOMO_PRIVACY_CONFIRMED', ''));
|
|
$cookieDomain = trim((string)app_env('MATOMO_CONSENT_COOKIE_DOMAIN', ''));
|
|
$hasAnySetting = $url !== '' || $siteId !== '' || $cookieDomain !== '';
|
|
|
|
if (!$hasAnySetting) {
|
|
return [];
|
|
}
|
|
|
|
$errors = [];
|
|
$urlParts = $url !== '' ? parse_url($url) : false;
|
|
if (
|
|
$url === ''
|
|
|| filter_var($url, FILTER_VALIDATE_URL) === false
|
|
|| !is_array($urlParts)
|
|
|| !in_array(strtolower((string)($urlParts['scheme'] ?? '')), ['http', 'https'], true)
|
|
|| trim((string)($urlParts['host'] ?? '')) === ''
|
|
|| isset($urlParts['user'])
|
|
|| isset($urlParts['pass'])
|
|
|| isset($urlParts['query'])
|
|
|| isset($urlParts['fragment'])
|
|
) {
|
|
$errors[] = 'MATOMO_URL muss eine vollständige HTTP(S)-Basis-URL ohne Query oder Fragment sein.';
|
|
} elseif (!app_is_dev() && strtolower((string)$urlParts['scheme']) !== 'https') {
|
|
$errors[] = 'MATOMO_URL muss außerhalb der Entwicklungsumgebung HTTPS verwenden.';
|
|
}
|
|
|
|
if (preg_match('/^[1-9][0-9]*$/', $siteId) !== 1) {
|
|
$errors[] = 'MATOMO_SITE_ID muss eine positive ganze Zahl sein.';
|
|
}
|
|
|
|
if ($privacyConfirmed !== '1') {
|
|
$errors[] = 'MATOMO_PRIVACY_CONFIRMED muss nach Prüfung der Matomo-Datenschutzeinstellungen auf 1 gesetzt werden.';
|
|
}
|
|
|
|
$cookieDomainHostname = ltrim(strtolower($cookieDomain), '.');
|
|
if ($cookieDomain !== '' && filter_var($cookieDomainHostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false) {
|
|
$errors[] = 'MATOMO_CONSENT_COOKIE_DOMAIN ist keine gültige Cookie-Domain.';
|
|
} elseif ($cookieDomain !== '') {
|
|
$hostBelongsToCookieDomain = static function (string $host) use ($cookieDomainHostname): bool {
|
|
$host = strtolower($host);
|
|
return $host === $cookieDomainHostname || str_ends_with($host, '.' . $cookieDomainHostname);
|
|
};
|
|
$appHost = trim((string)app_primary_host());
|
|
$marketingHost = (string)parse_url((string)app_env('APP_MARKETING_URL', ''), PHP_URL_HOST);
|
|
if ($appHost !== '' && !$hostBelongsToCookieDomain($appHost)) {
|
|
$errors[] = 'MATOMO_CONSENT_COOKIE_DOMAIN passt nicht zu APP_HOST.';
|
|
}
|
|
if ($marketingHost !== '' && !$hostBelongsToCookieDomain($marketingHost)) {
|
|
$errors[] = 'MATOMO_CONSENT_COOKIE_DOMAIN passt nicht zu APP_MARKETING_URL.';
|
|
}
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
/**
|
|
* @return array{matomoUrl: string, siteId: string, consentCookie: string, consentVersion: string, consentMaxAge: int, cookieDomain: string, secureCookies: bool}|null
|
|
*/
|
|
function app_matomo_configuration(): ?array
|
|
{
|
|
$url = trim((string)app_env('MATOMO_URL', ''));
|
|
$siteId = trim((string)app_env('MATOMO_SITE_ID', ''));
|
|
$privacyConfirmed = trim((string)app_env('MATOMO_PRIVACY_CONFIRMED', ''));
|
|
|
|
if ($url === '' && $siteId === '') {
|
|
return null;
|
|
}
|
|
if (app_matomo_configuration_errors() !== []) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'matomoUrl' => rtrim($url, '/') . '/',
|
|
'siteId' => $siteId,
|
|
'consentCookie' => APP_ANALYTICS_CONSENT_COOKIE,
|
|
'consentVersion' => APP_ANALYTICS_CONSENT_VERSION,
|
|
'consentMaxAge' => APP_ANALYTICS_CONSENT_MAX_AGE,
|
|
'cookieDomain' => trim((string)app_env('MATOMO_CONSENT_COOKIE_DOMAIN', '')),
|
|
'secureCookies' => app_is_https(),
|
|
];
|
|
}
|
|
|
|
function app_analytics_head_html(): string
|
|
{
|
|
if (app_matomo_configuration() === null) {
|
|
return '';
|
|
}
|
|
|
|
return '<link rel="stylesheet" href="assets/css/analytics-consent.css">' . "\n";
|
|
}
|
|
|
|
function app_analytics_body_html(): string
|
|
{
|
|
$configuration = app_matomo_configuration();
|
|
if ($configuration === null) {
|
|
return '';
|
|
}
|
|
|
|
$json = json_encode(
|
|
$configuration,
|
|
JSON_UNESCAPED_SLASHES
|
|
| JSON_UNESCAPED_UNICODE
|
|
| JSON_HEX_TAG
|
|
| JSON_HEX_AMP
|
|
| JSON_HEX_APOS
|
|
| JSON_HEX_QUOT
|
|
);
|
|
if (!is_string($json)) {
|
|
return '';
|
|
}
|
|
|
|
return <<<'HTML'
|
|
<section class="analytics-consent" id="analytics-consent" aria-labelledby="analytics-consent-title" aria-describedby="analytics-consent-description" hidden>
|
|
<div class="analytics-consent__inner">
|
|
<div class="analytics-consent__copy">
|
|
<h2 id="analytics-consent-title">Optionale Nutzungsanalyse</h2>
|
|
<p id="analytics-consent-description">Wir möchten mit Matomo verstehen, wie unsere Website und App genutzt werden. Erst nach deiner Zustimmung laden wir Matomo und setzen Analyse-Cookies. Notwendige Cookies funktionieren immer. Mehr dazu steht im <a href="datenschutz.php">Datenschutz</a>.</p>
|
|
</div>
|
|
<div class="analytics-consent__actions">
|
|
<button type="button" data-analytics-consent="denied">Nur notwendige</button>
|
|
<button type="button" data-analytics-consent="granted">Analyse erlauben</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<button type="button" class="analytics-consent-settings" id="analytics-consent-settings" hidden>Cookie-Einstellungen</button>
|
|
HTML
|
|
. "\n<script type=\"application/json\" id=\"analytics-configuration\">{$json}</script>\n"
|
|
. '<script src="assets/js/analytics-consent.js" defer></script>' . "\n";
|
|
}
|