shop-old/core/revocationhelper.class.php
2026-04-20 01:03:43 +02:00

110 lines
2.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Carteasy RevocationHelper
*
* Static helpers für Widerruf nach EU-RL 2026/2673.
* Bewusst ohne DB-State, nur Pure-Functions.
*
* @copyright Wlanium / Thomas Bartelt
* @since 2026-04-19
*/
include_once $_SERVER['DOCUMENT_ROOT'].'/core/config/revocation_config.inc.php';
class RevocationHelper {
/**
* Prüft, ob eine Kundengruppe zum elektronischen Widerruf berechtigt ist.
*/
public static function is_b2c($customer_group_id) {
$b2c = unserialize(REVOCATION_B2C_GROUP_IDS);
return in_array((int)$customer_group_id, $b2c, true);
}
/**
* Liefert die customer_group_id für eine Bestellung.
* Bei Gast (customer_id NULL) → REVOCATION_GUEST_GROUP_ID (103).
* Sonst aus customer-Tabelle gezogen.
*/
public static function resolve_group_id($db, $customer_id) {
if (empty($customer_id)) {
return REVOCATION_GUEST_GROUP_ID;
}
$customer_id = (int)$customer_id;
$sql = "SELECT customer_group_id FROM customers WHERE id = $customer_id LIMIT 1";
$result = $db->query($sql);
if ($result && $result->num_rows > 0) {
$row = $result->fetch_object();
return (int)$row->customer_group_id;
}
return 0;
}
/**
* Erzeugt ein kryptographisch zufälliges Token (Hex).
*/
public static function generate_token() {
return bin2hex(random_bytes(REVOCATION_TOKEN_BYTES));
}
/**
* SHA-256 des Klartext-Tokens. Nur dieser Hash wird persistiert.
*/
public static function hash_token($token_plain) {
return hash('sha256', $token_plain);
}
/**
* Baut die vollständige Widerrufs-URL für eine Bestell-Mail.
*/
public static function build_link($token_plain, $host = null) {
if ($host === null) {
$host = (isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'])
? $_SERVER['HTTP_HOST']
: 'www.intelectra.de';
}
return 'https://' . $host . REVOCATION_LANDING_PATH
. '?t=' . urlencode($token_plain);
}
/**
* DSGVO-konforme IP-Anonymisierung.
* IPv4: letztes Oktett auf 0 (/24)
* IPv6: letzte 80 Bits auf 0 (/48)
* Ungültige Eingabe → NULL.
*/
public static function anonymize_ip($ip) {
if (empty($ip)) {
return null;
}
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$parts = explode('.', $ip);
$parts[3] = '0';
return implode('.', $parts);
}
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$bin = inet_pton($ip);
if ($bin === false) return null;
// /48: erste 6 Bytes behalten, Rest auf 0
$masked = substr($bin, 0, 6) . str_repeat("\0", 10);
return inet_ntop($masked);
}
return null;
}
/**
* Berechnet den expires_at-Timestamp ab einem Basis-Datum.
* $base_date: 'YYYY-MM-DD' aus orders.order_date, oder null → jetzt.
*/
public static function calc_expires_at($base_date = null) {
$days = (int) REVOCATION_TOKEN_VALIDITY_DAYS;
if (!empty($base_date)) {
$ts = strtotime($base_date);
if ($ts === false) $ts = time();
} else {
$ts = time();
}
return date('Y-m-d H:i:s', $ts + $days * 86400);
}
}