// ==================== COINS & PROFILE DESIGN ==================== function ensureUserWallet($user_id) { global $pdo; $user_id = (int)$user_id; if($user_id <= 0) return false; try { $stmt = $pdo->prepare("INSERT IGNORE INTO user_wallets (user_id, coins) VALUES (?, 0)"); $stmt->execute([$user_id]); return true; } catch(PDOException $e) { return false; } } function getUserCoins($user_id) { global $pdo; $user_id = (int)$user_id; if($user_id <= 0) return 0; ensureUserWallet($user_id); $stmt = $pdo->prepare("SELECT coins FROM user_wallets WHERE user_id = ? LIMIT 1"); $stmt->execute([$user_id]); $row = $stmt->fetch(); return $row ? (int)$row['coins'] : 0; } function addUserCoins($user_id, $amount) { global $pdo; $user_id = (int)$user_id; $amount = (int)$amount; if($user_id <= 0 || $amount <= 0) return false; ensureUserWallet($user_id); $stmt = $pdo->prepare("UPDATE user_wallets SET coins = coins + ?, updated_at = NOW() WHERE user_id = ?"); return $stmt->execute([$amount, $user_id]); } function subtractUserCoins($user_id, $amount) { global $pdo; $user_id = (int)$user_id; $amount = (int)$amount; if($user_id <= 0 || $amount <= 0) return false; ensureUserWallet($user_id); // atomar & sicher $stmt = $pdo->prepare("UPDATE user_wallets SET coins = coins - ?, updated_at = NOW() WHERE user_id = ? AND coins >= ?"); $stmt->execute([$amount, $user_id, $amount]); return $stmt->rowCount() > 0; } // Cache für Design-Daten (pro Request) $GLOBALS['user_design_cache'] = []; function getUserDesign($user_id) { global $pdo; $user_id = (int)$user_id; if($user_id <= 0) return null; if(isset($GLOBALS['user_design_cache'][$user_id])) { return $GLOBALS['user_design_cache'][$user_id]; } try { $stmt = $pdo->prepare(" SELECT upd.user_id, ns.data_json AS name_style_data, nc.data_json AS name_color_data, af.data_json AS avatar_frame_data FROM user_profile_design upd LEFT JOIN profile_items ns ON ns.id = upd.active_name_style_item_id LEFT JOIN profile_items nc ON nc.id = upd.active_name_color_item_id LEFT JOIN profile_items af ON af.id = upd.active_avatar_frame_item_id WHERE upd.user_id = ? LIMIT 1 "); $stmt->execute([$user_id]); $row = $stmt->fetch(); if(!$row) { // lege default-zeile an $stmt2 = $pdo->prepare("INSERT IGNORE INTO user_profile_design (user_id) VALUES (?)"); $stmt2->execute([$user_id]); $GLOBALS['user_design_cache'][$user_id] = [ 'name_style' => null, 'name_color' => null, 'avatar_frame' => null ]; return $GLOBALS['user_design_cache'][$user_id]; } $name_style = $row['name_style_data'] ? json_decode($row['name_style_data'], true) : null; $name_color = $row['name_color_data'] ? json_decode($row['name_color_data'], true) : null; $avatar_frame = $row['avatar_frame_data'] ? json_decode($row['avatar_frame_data'], true) : null; $GLOBALS['user_design_cache'][$user_id] = [ 'name_style' => $name_style, 'name_color' => $name_color, 'avatar_frame' => $avatar_frame ]; return $GLOBALS['user_design_cache'][$user_id]; } catch(PDOException $e) { return null; } } function renderUsername($user_id, $username) { $username_clean = clean($username); $design = getUserDesign($user_id); $classes = ['jx-username']; $style_parts = []; if($design && !empty($design['name_style']['class'])) { $classes[] = preg_replace('/[^a-zA-Z0-9_-]/', '', $design['name_style']['class']); } if($design && !empty($design['name_color']['color'])) { $color = $design['name_color']['color']; // simple allowlist: hex colors only if(preg_match('/^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/', $color)) { $style_parts[] = "color: {$color}"; } } $style_attr = $style_parts ? ' style="'.implode('; ', $style_parts).'"' : ''; return ''.$username_clean.''; } function getAvatarFrameClass($user_id) { $design = getUserDesign($user_id); if($design && !empty($design['avatar_frame']['class'])) { return preg_replace('/[^a-zA-Z0-9_-]/', '', $design['avatar_frame']['class']); } return ''; } JX Social - Login
E-Mail Passwort Username