Initial import: Carteasy Shop (Dev-Stand)

This commit is contained in:
Thomas Bartelt
2026-04-20 01:03:43 +02:00
commit d504f8a05d
3845 changed files with 761050 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
<?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);
}
}