Enhance cookie consent management and UI improvements

This commit refines the cookie consent management system by introducing a new function for handling cookie preferences and updating the UI elements in `inc_footer.php` and `inc_header.php`. It ensures that analytics and marketing scripts are executed based on user consent, improving compliance with privacy regulations. Additionally, it enhances the cookie consent interface, providing users with clearer options for managing their cookie preferences, and updates related functions for better maintainability.
This commit is contained in:
2026-06-27 14:48:48 -04:00
parent 19679875df
commit ce7c430046
8 changed files with 673 additions and 66 deletions

View File

@ -114,7 +114,7 @@ if (isset($tabEvenement) && $tabEvenement['general']['eve_commanditaires'] == "1
<div class="social">
<a href="http://www.facebook.com/pages/Ms1timing/387594717971765" target="_blank"><i class="fa fa-facebook-square"></i></a>
<a href="https://twitter.com/ms1timing" target="_blank"><i class="fa fa-twitter-square"></i></a>
<a href="<?php echo htmlspecialchars($_SERVER['REQUEST_URI']); ?><?php echo (strpos($_SERVER['REQUEST_URI'], '?') === false) ? '?' : '&'; ?>cookies=1" title="<?php echo ($strLangue === 'fr') ? 'Gérer les témoins' : 'Manage cookies'; ?>"><img style="border: none;" width="30" src="<?php echo $vDomaine; ?>/images/cookie.svg" alt="cookies" /></a>
<a href="#" class="cookie-manage-link" data-cookie-manage title="<?php echo ($strLangue === 'fr') ? 'Gérer les témoins' : 'Manage cookies'; ?>"><img style="border: none;" width="30" height="30" src="<?php echo $vDomaine; ?>/images/cookie.svg" alt="<?php echo ($strLangue === 'fr') ? 'Gérer les témoins' : 'Manage cookies'; ?>" /></a>
</div>
</div>
</div>
@ -187,7 +187,16 @@ if (isset($tabEvenement) && $tabEvenement['general']['eve_commanditaires'] == "1
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 10px;
gap: 12px;
text-align: center;
}
.cookie-consent-container p {
flex: 1 1 100%;
max-width: 900px;
margin: 0 auto 8px;
font-size: 14px;
line-height: 1.5;
}
.cookie-consent-actions {
@ -200,6 +209,23 @@ if (isset($tabEvenement) && $tabEvenement['general']['eve_commanditaires'] == "1
.cookie-consent-links {
margin-top: 10px;
text-align: center;
font-size: 13px;
}
.cookie-consent-links a {
color: #0066cc;
text-decoration: underline;
}
.ms1-footer-top .social a.cookie-manage-link {
display: inline-block;
vertical-align: middle;
margin-left: 6px;
opacity: 0.9;
}
.ms1-footer-top .social a.cookie-manage-link:hover {
opacity: 1;
}
#acceptCookies, #rejectCookies {
@ -225,6 +251,47 @@ if (isset($tabEvenement) && $tabEvenement['general']['eve_commanditaires'] == "1
background-color: #e53935;
}
#cookiePreferencesPanel {
max-width: 640px;
margin: 12px auto 0;
padding: 12px 16px;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
text-align: left;
}
.cookie-pref-row {
display: flex;
align-items: flex-start;
gap: 10px;
margin-bottom: 10px;
}
.cookie-pref-row label {
margin: 0;
font-weight: normal;
font-size: 13px;
}
.cookie-pref-row input[type="checkbox"] {
margin-top: 3px;
}
#customizeCookies, #saveCookiePreferences {
background: #666;
border-radius: 5px;
color: white;
border: none;
padding: 10px 20px;
cursor: pointer;
font-size: 12px;
}
#saveCookiePreferences {
background: #333;
}
</style>
<!-- MSIN-3860 -->
@ -235,64 +302,37 @@ if (isset($tabEvenement) && $tabEvenement['general']['eve_commanditaires'] == "1
<div class="cookie-consent-actions">
<button type="button" id="acceptCookies"><?php echo fxCookieConsentText('bouton_acceper_cookies', $strLangue); ?></button>
<button type="button" id="rejectCookies"><?php echo fxCookieConsentText('bouton_refuser_cookies', $strLangue); ?></button>
<button type="button" id="customizeCookies"><?php echo fxCookieConsentText('bouton_personnaliser_cookies', $strLangue); ?></button>
</div>
</div>
<div id="cookiePreferencesPanel" class="cookie-consent-container d-none">
<p><strong><?php echo fxCookieConsentText('cookie_pref_titre', $strLangue); ?></strong></p>
<div class="cookie-pref-row">
<input type="checkbox" id="cookiePrefEssential" checked disabled>
<label for="cookiePrefEssential"><?php echo fxCookieConsentText('cookie_pref_essentiels', $strLangue); ?></label>
</div>
<div class="cookie-pref-row">
<input type="checkbox" id="cookiePrefAnalytics">
<label for="cookiePrefAnalytics"><?php echo fxCookieConsentText('cookie_pref_analytique', $strLangue); ?></label>
</div>
<div class="cookie-pref-row">
<input type="checkbox" id="cookiePrefMarketing">
<label for="cookiePrefMarketing"><?php echo fxCookieConsentText('cookie_pref_marketing', $strLangue); ?></label>
</div>
<div class="cookie-consent-actions">
<button type="button" id="saveCookiePreferences"><?php echo fxCookieConsentText('bouton_enregistrer_cookies', $strLangue); ?></button>
</div>
</div>
<div class="cookie-consent-links">
<a href="<?php echo $vDomaine; ?>/page/cookie/<?php echo $strLangue; ?>"><?php echo fxCookieConsentText('politique_cookie', $strLangue); ?></a>
&nbsp;|&nbsp;
<a href="<?php echo $vDomaine; ?>/page/confidentialite/<?php echo $strLangue; ?>"><?php echo fxCookieConsentText('politique_confidentialite', $strLangue); ?></a>
</div>
</div>
<?php require_once 'inc_footer_scripts.php'; ?>
<script>
function setCookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
document.cookie = cname + "=" + cvalue + ";expires=" + d.toUTCString() + ";path=/;SameSite=Lax";
}
function deleteCookie(cname) {
document.cookie = cname + "=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;SameSite=Lax";
}
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
$(function () {
if (!getCookie('cookiesAccepted') && !getCookie('cookiesRejected')) {
$('#cookieConsent').fadeIn();
}
$('#acceptCookies').on('click', function () {
deleteCookie('cookiesRejected');
setCookie('cookiesAccepted', 'true', 365);
window.location.reload();
});
$('#rejectCookies').on('click', function () {
deleteCookie('cookiesAccepted');
setCookie('cookiesRejected', 'true', 365);
$('#cookieConsent').fadeOut();
});
});
</script>
<script src="<?php echo $vDomaine; ?>/js/cookie-consent.js?version=v<?php echo _VERSION_CODE; ?>"></script>
</body>
</html>

View File

@ -6,7 +6,9 @@ if (fxCookiesAllowMarketing()) {
if (isset($tabEvenement['general']) && trim($tabEvenement['general']['eve_plugins']) != '') {
echo trim($tabEvenement['general']['eve_plugins']);
}
}
if (fxCookiesAllowAnalytics()) {
echo $vGoogleAnalytics;
}

View File

@ -137,7 +137,9 @@ if (!isset($strOGDescription)) {
-->
<!-- apres migration des info paypal pour MSIN-4216
affaire remplacer echo PAYPAL_CLIENT_ID; -->
<?php if (fxPageNeedsPaypal()) { ?>
<script src="https://www.paypal.com/sdk/js?components=card-fields,buttons,googlepay&client-id=<?php echo PAYPAL_CLIENT_ID; ?>&disable-funding=paylater,credit&currency=CAD<?php echo $strPaypalLangue; ?>"></script>
<?php } ?>

View File

@ -65,8 +65,13 @@ require_once("inc_header.php");
<?php
switch ($strCode) {
case 'cookie':
$strCookieContent = trim((string) $recPage['pag_texte_' . $strLangue]);
echo $strCookieContent !== '' ? fxUnescape($recPage['pag_texte_' . $strLangue], 1) : fxCookiePolicyPageContent($strLangue);
break;
echo fxUnescape($recPage['pag_texte_' . $strLangue], 1);
case 'confidentialite':
$strPrivacyContent = trim((string) $recPage['pag_texte_' . $strLangue]);
echo $strPrivacyContent !== '' ? fxUnescape($recPage['pag_texte_' . $strLangue], 1) : fxPrivacyPolicyPageContent($strLangue);
break;
case 'evenements':

142
js/cookie-consent.js Normal file
View File

@ -0,0 +1,142 @@
(function (window, $) {
'use strict';
var STORAGE_KEY = 'cookiesPreferences';
var LEGACY_ACCEPT = 'cookiesAccepted';
var LEGACY_REJECT = 'cookiesRejected';
function setCookie(name, value, days) {
var expires = '';
if (typeof days === 'number') {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = ';expires=' + date.toUTCString();
}
document.cookie = name + '=' + encodeURIComponent(value) + expires + ';path=/;SameSite=Lax';
}
function deleteCookie(name) {
document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;SameSite=Lax';
}
function getCookie(name) {
var prefix = name + '=';
var parts = decodeURIComponent(document.cookie).split(';');
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
while (part.charAt(0) === ' ') {
part = part.substring(1);
}
if (part.indexOf(prefix) === 0) {
return part.substring(prefix.length);
}
}
return '';
}
function readPreferences() {
var raw = getCookie(STORAGE_KEY);
if (raw) {
try {
var parsed = JSON.parse(raw);
if (parsed && typeof parsed === 'object') {
return {
analytics: !!parsed.analytics,
marketing: !!parsed.marketing,
set: true
};
}
} catch (e) {
}
}
if (getCookie(LEGACY_ACCEPT) === 'true') {
return { analytics: true, marketing: true, set: true };
}
if (getCookie(LEGACY_REJECT) === 'true') {
return { analytics: false, marketing: false, set: true };
}
return { analytics: false, marketing: false, set: false };
}
function writePreferences(prefs, reload) {
deleteCookie(LEGACY_ACCEPT);
deleteCookie(LEGACY_REJECT);
setCookie(STORAGE_KEY, JSON.stringify({
analytics: prefs.analytics ? 1 : 0,
marketing: prefs.marketing ? 1 : 0,
v: 1
}), 365);
if (reload !== false) {
window.location.reload();
}
}
function syncPanel(prefs) {
$('#cookiePrefAnalytics').prop('checked', !!prefs.analytics);
$('#cookiePrefMarketing').prop('checked', !!prefs.marketing);
}
function openBanner() {
$('#cookieConsent').stop(true, true).fadeIn(200);
}
function closeBanner() {
$('#cookieConsent').stop(true, true).fadeOut(200);
$('#cookiePreferencesPanel').addClass('d-none');
}
window.ms1CookieConsent = {
getPreferences: readPreferences,
openManager: function () {
syncPanel(readPreferences());
$('#cookiePreferencesPanel').removeClass('d-none');
openBanner();
}
};
$(function () {
var prefs = readPreferences();
syncPanel(prefs);
if (!prefs.set) {
openBanner();
}
$('#acceptCookies').on('click', function () {
writePreferences({ analytics: true, marketing: true });
});
$('#rejectCookies').on('click', function () {
writePreferences({ analytics: false, marketing: false });
});
$('#customizeCookies').on('click', function () {
$('#cookiePreferencesPanel').removeClass('d-none');
});
$('#saveCookiePreferences').on('click', function () {
writePreferences({
analytics: $('#cookiePrefAnalytics').is(':checked'),
marketing: $('#cookiePrefMarketing').is(':checked')
});
});
$('[data-cookie-manage]').on('click', function (event) {
event.preventDefault();
window.ms1CookieConsent.openManager();
});
});
}(window, jQuery));

View File

@ -1,23 +1,59 @@
<?php
function fxCookiesPreferences(): array
{
$defaults = ['analytics' => false, 'marketing' => false, 'set' => false];
if (!empty($_COOKIE['cookiesPreferences'])) {
$prefs = json_decode(stripslashes((string) $_COOKIE['cookiesPreferences']), true);
if (is_array($prefs)) {
return [
'analytics' => !empty($prefs['analytics']),
'marketing' => !empty($prefs['marketing']),
'set' => true,
];
}
}
if (isset($_COOKIE['cookiesAccepted']) && $_COOKIE['cookiesAccepted'] === 'true') {
return ['analytics' => true, 'marketing' => true, 'set' => true];
}
if (isset($_COOKIE['cookiesRejected']) && $_COOKIE['cookiesRejected'] === 'true') {
return ['analytics' => false, 'marketing' => false, 'set' => true];
}
return $defaults;
}
function fxCookiesConsentAccepted(): bool
{
return isset($_COOKIE['cookiesAccepted']) && $_COOKIE['cookiesAccepted'] === 'true';
$prefs = fxCookiesPreferences();
return $prefs['set'] && ($prefs['analytics'] || $prefs['marketing']);
}
function fxCookiesConsentRejected(): bool
{
return isset($_COOKIE['cookiesRejected']) && $_COOKIE['cookiesRejected'] === 'true';
$prefs = fxCookiesPreferences();
return $prefs['set'] && !$prefs['analytics'] && !$prefs['marketing'];
}
function fxCookiesConsentPending(): bool
{
return !fxCookiesConsentAccepted() && !fxCookiesConsentRejected();
return !fxCookiesPreferences()['set'];
}
function fxCookiesAllowAnalytics(): bool
{
return fxCookiesPreferences()['analytics'];
}
function fxCookiesAllowMarketing(): bool
{
return fxCookiesConsentAccepted();
return fxCookiesPreferences()['marketing'];
}
function fxCookiesConsentResetIfRequested(): void
@ -27,9 +63,12 @@ function fxCookiesConsentResetIfRequested(): void
}
$past = time() - 3600;
setcookie('cookiesAccepted', '', $past, '/');
setcookie('cookiesRejected', '', $past, '/');
unset($_COOKIE['cookiesAccepted'], $_COOKIE['cookiesRejected']);
$names = ['cookiesAccepted', 'cookiesRejected', 'cookiesPreferences'];
foreach ($names as $name) {
setcookie($name, '', $past, '/');
unset($_COOKIE[$name]);
}
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?: '/';
$query = [];
@ -49,12 +88,33 @@ function fxCookiesConsentResetIfRequested(): void
exit;
}
function fxCookieConsentText(string $clef, string $strLangue): string
function fxPageNeedsPaypal(): bool
{
$defaults = [
global $strPage;
if (empty($strPage)) {
return false;
}
static $paypalPages = [
'panier.php',
'dons.php',
'paiement_redirect.php',
'panier',
'cart',
'don',
'donate',
];
return in_array($strPage, $paypalPages, true);
}
function fxCookieConsentDefaults(): array
{
return [
'experience_cookies' => [
'fr' => 'Nous utilisons des témoins (cookies) pour assurer le bon fonctionnement du site et, avec votre consentement, mesurer l\'audience. Vous pouvez accepter ou refuser les témoins non essentiels sans affecter votre inscription.',
'en' => 'We use cookies to ensure the site works properly and, with your consent, measure traffic. You may accept or refuse non-essential cookies without affecting your registration.',
'fr' => 'Ce site utilise des témoins essentiels au fonctionnement de vos inscriptions. Avec votre permission, nous utilisons aussi des témoins de mesure d\'audience et de marketing. Vous pouvez accepter, refuser ou personnaliser vos choix.',
'en' => 'This site uses essential cookies for registration. With your permission, we also use analytics and marketing cookies. You may accept, refuse or customize your choices.',
],
'bouton_acceper_cookies' => [
'fr' => 'Tout accepter',
@ -64,12 +124,115 @@ function fxCookieConsentText(string $clef, string $strLangue): string
'fr' => 'Tout refuser',
'en' => 'Refuse all',
],
'bouton_personnaliser_cookies' => [
'fr' => 'Personnaliser',
'en' => 'Customize',
],
'bouton_enregistrer_cookies' => [
'fr' => 'Enregistrer mes choix',
'en' => 'Save my choices',
],
'cookie_pref_titre' => [
'fr' => 'Préférences de témoins',
'en' => 'Cookie preferences',
],
'cookie_pref_essentiels' => [
'fr' => 'Essentiels — requis pour le panier, la session et la sécurité. Toujours actifs.',
'en' => 'Essential — required for cart, session and security. Always active.',
],
'cookie_pref_analytique' => [
'fr' => 'Mesure d\'audience — statistiques anonymes de fréquentation (Google Analytics).',
'en' => 'Analytics — anonymous traffic statistics (Google Analytics).',
],
'cookie_pref_marketing' => [
'fr' => 'Marketing — mesure publicitaire et remarketing (Facebook / Meta, scripts événement).',
'en' => 'Marketing — advertising measurement and remarketing (Facebook / Meta, event scripts).',
],
'politique_cookie' => [
'fr' => 'Politique de témoins',
'en' => 'Cookie policy',
],
'politique_confidentialite' => [
'fr' => 'Politique de confidentialité',
'en' => 'Privacy policy',
],
];
}
function fxCookieConsentTextIsDraft(string $clef, string $text): bool
{
$text = trim($text);
if ($text === '' || $text === $clef || $text === '*' . $clef . '*') {
return true;
}
if (stripos($text, $clef) === 0) {
return true;
}
return false;
}
function fxEnsureCookieConsentTexts(): void
{
global $objDatabase;
if (!isset($objDatabase)) {
return;
}
static $done = false;
if ($done) {
return;
}
$done = true;
foreach (fxCookieConsentDefaults() as $clef => $texts) {
foreach (['fr', 'en'] as $lang) {
if (!isset($texts[$lang])) {
continue;
}
$sql = "SELECT pk_info, info_texte FROM info
WHERE info_clef = '" . $objDatabase->fxEscape($clef) . "'
AND info_langue = '" . $objDatabase->fxEscape($lang) . "'
AND info_prg = 'global'
LIMIT 1";
$row = $objDatabase->fxGetRow($sql);
if (!$row) {
if (function_exists('fxSetInfo')) {
fxSetInfo('add', [
'info_clef' => $clef,
'info_langue' => $lang,
'info_texte' => $texts[$lang],
'info_aide' => '',
'info_prg' => 'global',
'info_actif' => 1,
], $lang);
}
continue;
}
if (!fxCookieConsentTextIsDraft($clef, (string) $row['info_texte'])) {
continue;
}
$objDatabase->fxQuery(
"UPDATE info SET info_texte = '" . $objDatabase->fxEscape($texts[$lang]) . "', info_maj = NOW()
WHERE pk_info = " . intval($row['pk_info'])
);
}
}
}
function fxCookieConsentText(string $clef, string $strLangue): string
{
$defaults = fxCookieConsentDefaults();
$lang = ($strLangue === 'en') ? 'en' : 'fr';
$fallback = $defaults[$clef][$lang] ?? $clef;
@ -77,11 +240,258 @@ function fxCookieConsentText(string $clef, string $strLangue): string
return $fallback;
}
$text = afficheTexte($clef, 0, 1, 1);
$text = trim((string) afficheTexte($clef, 0, 1, 1));
if ($text === '' || $text === $clef || $text === '*' . $clef . '*') {
if (fxCookieConsentTextIsDraft($clef, $text)) {
return $fallback;
}
return $text;
}
function fxCookieLegalPlaceholders(string $html): string
{
global $vClient, $vDomaine;
$org = htmlspecialchars((string) $vClient, ENT_QUOTES, 'UTF-8');
$domain = htmlspecialchars((string) $vDomaine, ENT_QUOTES, 'UTF-8');
$email = 'confidentialite@' . preg_replace('/^https?:\/\//', '', (string) parse_url($vDomaine, PHP_URL_HOST));
$date = date('Y-m-d');
$replacements = [
'[ORGANISATION]' => $org,
'[ORGANIZATION]' => $org,
'[SITE]' => $domain,
'[DATE]' => $date,
'[COURRIEL]' => $email,
'[EMAIL]' => $email,
];
return str_replace(array_keys($replacements), array_values($replacements), $html);
}
function fxCookiePolicyHtml(string $strLangue): string
{
if ($strLangue === 'en') {
return fxCookieLegalPlaceholders(<<<'HTML'
<h2>Cookie policy</h2>
<p><strong>Last updated:</strong> [DATE]</p>
<p><strong>[ORGANIZATION]</strong> uses cookies on its registration site operated via MS1 Inscription (Progiweb inc.).</p>
<h3>1. Essential cookies (always active)</h3>
<ul>
<li><strong>PHP session</strong> — cart, login and forms (~3 h inactivity)</li>
<li><strong>no_panier</strong> — cart identifier (10 hours)</li>
<li><strong>cookiesPreferences</strong> — remembers your choices (12 months)</li>
<li><strong>reCAPTCHA (Google)</strong> — spam protection on forms</li>
</ul>
<h3>2. Analytics cookies (optional)</h3>
<p>Google Analytics (_ga, _gid) — only if you enable analytics in the banner.</p>
<h3>3. Marketing cookies (optional)</h3>
<p>Meta Pixel (_fbp) and event-specific scripts — only if you enable marketing in the banner.</p>
<h3>4. Payment cookies</h3>
<p>PayPal cookies may be placed during checkout only.</p>
<h3>5. Your rights</h3>
<p>Contact: [EMAIL]. You may reset your choices anytime using the cookie icon in the footer or by adding <code>?cookies=1</code> to the URL.</p>
<p>See also our <a href="[SITE]/page/confidentialite/en">privacy policy</a>.</p>
HTML
);
}
return fxCookieLegalPlaceholders(<<<'HTML'
<h2>Politique de témoins</h2>
<p><strong>Dernière mise à jour :</strong> [DATE]</p>
<p><strong>[ORGANISATION]</strong> utilise des témoins sur son site d'inscription exploité via MS1 Inscription (Progiweb inc.).</p>
<h3>1. Témoins essentiels (toujours actifs)</h3>
<ul>
<li><strong>Session PHP</strong> — panier, connexion et formulaires (~3 h d'inactivité)</li>
<li><strong>no_panier</strong> — identifiant du panier (10 heures)</li>
<li><strong>cookiesPreferences</strong> — mémorise vos choix (12 mois)</li>
<li><strong>reCAPTCHA (Google)</strong> — protection anti-pourriel sur les formulaires</li>
</ul>
<h3>2. Témoins analytiques (optionnels)</h3>
<p>Google Analytics (_ga, _gid) — uniquement si vous activez la mesure d'audience dans le bandeau.</p>
<h3>3. Témoins marketing (optionnels)</h3>
<p>Pixel Meta (_fbp) et scripts spécifiques à l'événement — uniquement si vous activez le marketing dans le bandeau.</p>
<h3>4. Témoins de paiement</h3>
<p>Des témoins PayPal peuvent être déposés lors du paiement seulement.</p>
<h3>5. Vos droits</h3>
<p>Contact : [COURRIEL]. Vous pouvez réinitialiser vos choix via l'icône témoins du pied de page ou en ajoutant <code>?cookies=1</code> à l'adresse.</p>
<p>Voir aussi notre <a href="[SITE]/page/confidentialite/fr">politique de confidentialité</a>.</p>
HTML
);
}
function fxPrivacyPolicyHtml(string $strLangue): string
{
if ($strLangue === 'en') {
return fxCookieLegalPlaceholders(<<<'HTML'
<h2>Privacy policy</h2>
<p><strong>Last updated:</strong> [DATE]</p>
<p><strong>[ORGANIZATION]</strong> collects personal information when you register for events on [SITE], in compliance with Quebec Law 25.</p>
<h3>Information collected</h3>
<p>Name, contact details, date of birth, registration choices, payment metadata (processed by PayPal — we do not store full card numbers), and technical data (IP, browser).</p>
<h3>Purposes</h3>
<ul>
<li>Process registrations and payments</li>
<li>Communicate about your order and the event</li>
<li>Secure the site and prevent fraud</li>
<li>Analytics and marketing only with your cookie consent</li>
</ul>
<h3>Third parties</h3>
<p>Progiweb (MS1 Inscription), PayPal, Google (reCAPTCHA, Analytics if consented), Meta (Pixel if consented), and the event organizer.</p>
<h3>Cross-border transfers</h3>
<p>Some providers may process data outside Quebec. Contractual safeguards are applied.</p>
<h3>Your rights</h3>
<p>Access, correction, deletion and withdrawal of consent: [EMAIL]. Response within 30 days when possible.</p>
<h3>Privacy officer</h3>
<p>Contact: [EMAIL]</p>
<p><a href="[SITE]/page/cookie/en">Cookie policy</a></p>
HTML
);
}
return fxCookieLegalPlaceholders(<<<'HTML'
<h2>Politique de confidentialité</h2>
<p><strong>Dernière mise à jour :</strong> [DATE]</p>
<p><strong>[ORGANISATION]</strong> collecte des renseignements personnels lors de vos inscriptions sur [SITE], conformément à la Loi 25.</p>
<h3>Renseignements collectés</h3>
<p>Nom, coordonnées, date de naissance, choix d'inscription, métadonnées de paiement (PayPal — aucun numéro de carte complet conservé), et données techniques (IP, navigateur).</p>
<h3>Finalités</h3>
<ul>
<li>Traiter les inscriptions et paiements</li>
<li>Communiquer au sujet de votre commande et de l'événement</li>
<li>Sécuriser le site et prévenir la fraude</li>
<li>Statistiques et marketing seulement avec votre consentement aux témoins</li>
</ul>
<h3>Tiers</h3>
<p>Progiweb (MS1 Inscription), PayPal, Google (reCAPTCHA, Analytics si consenti), Meta (Pixel si consenti), et l'organisateur de l'événement.</p>
<h3>Transferts hors Québec</h3>
<p>Certains mandataires peuvent traiter des données à l'extérieur du Québec. Des mesures contractuelles s'appliquent.</p>
<h3>Vos droits</h3>
<p>Accès, rectification, suppression et retrait du consentement : [COURRIEL]. Réponse dans un délai de 30 jours lorsque possible.</p>
<h3>Responsable de la protection des renseignements personnels</h3>
<p>Contact : [COURRIEL]</p>
<p><a href="[SITE]/page/cookie/fr">Politique de témoins</a></p>
HTML
);
}
function fxEnsureLegalPage(string $code, string $labelFr, string $labelEn, string $titleFr, string $titleEn, callable $bodyFr, callable $bodyEn, int $sort = 90): void
{
global $objDatabase;
if (!isset($objDatabase)) {
return;
}
$sql = "SELECT * FROM inscriptions_pages WHERE pag_code = '" . $objDatabase->fxEscape($code) . "' LIMIT 1";
$row = $objDatabase->fxGetRow($sql);
$textFr = $bodyFr();
$textEn = $bodyEn();
if (!$row) {
$sqlInsert = "INSERT INTO inscriptions_pages
(pag_code, pag_label_fr, pag_label_en, pag_titre_fr, pag_titre_en, pag_texte_fr, pag_texte_en, pag_tri, pag_maj, pag_menu, pag_actif)
VALUES (
'" . $objDatabase->fxEscape($code) . "',
'" . $objDatabase->fxEscape($labelFr) . "',
'" . $objDatabase->fxEscape($labelEn) . "',
'" . $objDatabase->fxEscape($titleFr) . "',
'" . $objDatabase->fxEscape($titleEn) . "',
'" . $objDatabase->fxEscape($textFr) . "',
'" . $objDatabase->fxEscape($textEn) . "',
" . intval($sort) . ",
NOW(),
1,
1
)";
$objDatabase->fxQuery($sqlInsert);
return;
}
$updates = [];
if (trim((string) $row['pag_texte_fr']) === '') {
$updates[] = "pag_texte_fr = '" . $objDatabase->fxEscape($textFr) . "'";
}
if (trim((string) $row['pag_texte_en']) === '') {
$updates[] = "pag_texte_en = '" . $objDatabase->fxEscape($textEn) . "'";
}
if (trim((string) $row['pag_titre_fr']) === '') {
$updates[] = "pag_titre_fr = '" . $objDatabase->fxEscape($titleFr) . "'";
}
if (trim((string) $row['pag_titre_en']) === '') {
$updates[] = "pag_titre_en = '" . $objDatabase->fxEscape($titleEn) . "'";
}
if ((int) $row['pag_menu'] !== 1) {
$updates[] = 'pag_menu = 1';
}
if ((int) $row['pag_actif'] !== 1) {
$updates[] = 'pag_actif = 1';
}
if ($updates) {
$updates[] = 'pag_maj = NOW()';
$objDatabase->fxQuery('UPDATE inscriptions_pages SET ' . implode(', ', $updates) . " WHERE pag_id = " . intval($row['pag_id']));
}
}
function fxEnsureLegalPages(): void
{
static $done = false;
if ($done) {
return;
}
$done = true;
fxEnsureCookieConsentTexts();
fxEnsureLegalPage(
'cookie',
'Témoins',
'Cookies',
'Politique de témoins',
'Cookie policy',
static function () {
return fxCookiePolicyHtml('fr');
},
static function () {
return fxCookiePolicyHtml('en');
},
98
);
fxEnsureLegalPage(
'confidentialite',
'Confidentialité',
'Privacy',
'Politique de confidentialité',
'Privacy policy',
static function () {
return fxPrivacyPolicyHtml('fr');
},
static function () {
return fxPrivacyPolicyHtml('en');
},
99
);
}
function fxCookiePolicyPageContent(string $strLangue): string
{
return fxCookiePolicyHtml($strLangue);
}
function fxPrivacyPolicyPageContent(string $strLangue): string
{
return fxPrivacyPolicyHtml($strLangue);
}

View File

@ -24,6 +24,8 @@ $objDatabase = new clsMysql($arrConDatabaseMain);
$objDatabaseProd= new clsMysql($arrConDatabaseProd);
$objDatabasePreProd= new clsMysql($arrConDatabasePreProd);
fxEnsureLegalPages();
//MSIN-3999
if (isset($_GET['preprod'])) {
$preprod = $_GET['preprod'];
@ -320,6 +322,10 @@ function fxGetPage($code)
$sqlPage = "SELECT * FROM inscriptions_pages WHERE pag_actif = 1 AND pag_code = '" . $objDatabase->fxEscape($code) . "'";
$recPage = $objDatabase->fxGetRow($sqlPage);
if (!$recPage) {
return [];
}
$recPage['pag_description_fr'] = fxGetNbWords($recPage['pag_texte_fr'], 50);
$recPage['pag_description_en'] = fxGetNbWords($recPage['pag_texte_en'], 50);

View File

@ -114,7 +114,7 @@ if ($tabMaintenance != null) {
</div>
</footer>
<?php if (fxCookiesAllowMarketing()) {
<?php if (fxCookiesAllowAnalytics()) {
echo $vGoogleAnalytics;
} ?>
<?php if (fxCookiesAllowMarketing()) { ?>