false, 'error' => 'Invalid JSON']); $username = isset($data['username']) ? trim((string)$data['username']) : ''; $email = isset($data['email']) ? trim((string)$data['email']) : ''; $password = isset($data['password']) ? (string)$data['password'] : ''; if ($username === '' || strlen($username) < 3 || strlen($username) > 32) { json_out(400, ['ok' => false, 'error' => 'Username must be 3-32 chars']); } if (!preg_match('/^[A-Za-z0-9_]+$/', $username)) { json_out(400, ['ok' => false, 'error' => 'Username must be letters/numbers/_ only']); } if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) { json_out(400, ['ok' => false, 'error' => 'Invalid email']); } if (strlen($password) < 6) { json_out(400, ['ok' => false, 'error' => 'Password must be at least 6 chars']); } $hash = password_hash($password, PASSWORD_DEFAULT); try { $stmt = $pdo->prepare('INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?)'); $stmt->execute([$username, ($email === '' ? null : $email), $hash]); $_SESSION['user_id'] = (int)$pdo->lastInsertId(); $u = current_user($pdo); json_out(201, ['ok' => true, 'user' => $u]); } catch (Throwable $e) { $msg = $e->getMessage(); if (stripos($msg, 'Duplicate') !== false || stripos($msg, 'uq_') !== false) { json_out(409, ['ok' => false, 'error' => 'Username or email already used']); } json_out(500, ['ok' => false, 'error' => 'Register failed']); }