'scan-rarity-L', 'E' => 'scan-rarity-E', 'R' => 'scan-rarity-R', 'U' => 'scan-rarity-U', 'C' => 'scan-rarity-C', default => 'scan-rarity-none', }; } function index_scan_rarity_label(?string $rarity): string { return match (index_scan_normalize_rarity($rarity)) { 'L' => 'Légendaire', 'E' => 'Épique', 'R' => 'Rare', 'U' => 'Peu commun', 'C' => 'Commun', default => 'Non définie', }; } function index_itemcustom_display_value($value): string { if ($value === null || $value === '') { return '0'; } if (is_numeric($value)) { $formatted = number_format((float) $value, 2, '.', ''); $formatted = rtrim(rtrim($formatted, '0'), '.'); return $formatted === '' ? '0' : $formatted; } return trim((string) $value) !== '' ? trim((string) $value) : '0'; } function index_itemcustom_stat_preview(?string $sign, $value, ?string $unit): string { $prefix = $sign === '-' ? '-' : ($sign === '+' ? '+' : ''); $displayValue = index_itemcustom_display_value($value); $displayUnit = trim((string) ($unit ?? '')); return trim($prefix . $displayValue . ($displayUnit !== '' ? ' ' . $displayUnit : '')); } function index_vanilla_description_html(?string $description): string { $description = trim((string) $description); if ($description === '') { return 'Aucune description.'; } if ($description !== strip_tags($description)) { return $description; } return nl2br(htmlspecialchars($description, ENT_QUOTES, 'UTF-8')); } function index_vanilla_uex_normalize_whitespace(string $value): string { return trim((string) preg_replace('/\s+/u', ' ', html_entity_decode(strip_tags($value), ENT_QUOTES | ENT_HTML5, 'UTF-8'))); } function index_vanilla_uex_normalize_search_text(string $value): string { $value = function_exists('mb_strtolower') ? mb_strtolower($value, 'UTF-8') : strtolower($value); $value = preg_replace('/[^[:alnum:]]+/u', ' ', $value); return trim((string) preg_replace('/\s+/u', ' ', $value)); } function index_vanilla_uex_title_matches_query(string $title, string $queryName): bool { $normalizedTitle = index_vanilla_uex_normalize_search_text($title); $normalizedQuery = index_vanilla_uex_normalize_search_text($queryName); if ($normalizedTitle === '' || $normalizedQuery === '') { return false; } if (strpos($normalizedTitle, $normalizedQuery) !== false) { return true; } $queryTokens = array_values(array_filter(explode(' ', $normalizedQuery), static function (string $token): bool { return preg_match('/\d/', $token) || strlen($token) >= 3; })); if ($queryTokens === []) { return false; } foreach ($queryTokens as $token) { if (strpos($normalizedTitle, $token) === false) { return false; } } return true; } function index_vanilla_uex_extract_price_value(string $rawPrice): ?int { $rawPrice = trim($rawPrice); if ($rawPrice === '') { return null; } if (!preg_match('/([0-9][0-9\s,\.]*)((?:\s*[KMB])?)\s*(?:A?UEC)\b/i', $rawPrice, $matches)) { return null; } $numberPart = preg_replace('/\s+/', '', (string) ($matches[1] ?? '')); $suffix = strtoupper(trim((string) ($matches[2] ?? ''))); if ($numberPart === '') { return null; } if ($suffix !== '') { if (substr_count($numberPart, ',') === 1 && strpos($numberPart, '.') === false) { $numberPart = str_replace(',', '.', $numberPart); } else { $numberPart = str_replace(',', '', $numberPart); } } else { if (strpos($numberPart, ',') !== false && strpos($numberPart, '.') !== false) { if (strrpos($numberPart, ',') > strrpos($numberPart, '.')) { $numberPart = str_replace('.', '', $numberPart); $numberPart = str_replace(',', '.', $numberPart); } else { $numberPart = str_replace(',', '', $numberPart); } } else { $numberPart = str_replace(',', '', $numberPart); } } if (!is_numeric($numberPart)) { return null; } $value = (float) $numberPart; $multiplier = match ($suffix) { 'K' => 1000, 'M' => 1000000, 'B' => 1000000000, default => 1, }; return (int) round($value * $multiplier); } function index_vanilla_uex_parse_estimate_from_html(string $html, string $queryName, int $sampleLimit = 10): array { $values = []; $chunks = preg_split('/]*>/i', $html) ?: []; foreach ($chunks as $chunk) { if (count($values) >= $sampleLimit) { break; } if (!preg_match('/]*class="text-bold"[^>]*>(.*?)<\/a>/is', $chunk, $titleMatches)) { continue; } $title = index_vanilla_uex_normalize_whitespace((string) ($titleMatches[1] ?? '')); if ($title === '' || !preg_match('/^WTS\b/i', $title) || !index_vanilla_uex_title_matches_query($title, $queryName)) { continue; } if (!preg_match('/]*>(.*?)<\/h4>/is', $chunk, $priceMatches)) { continue; } $priceValue = index_vanilla_uex_extract_price_value(index_vanilla_uex_normalize_whitespace((string) ($priceMatches[1] ?? ''))); if ($priceValue === null) { continue; } $values[] = $priceValue; } if ($values === []) { return [ 'has_estimate' => false, 'average' => null, 'formatted' => '—', 'sample_count' => 0, ]; } $average = (int) round(array_sum($values) / count($values)); return [ 'has_estimate' => true, 'average' => $average, 'formatted' => '~' . number_format($average, 0, ',', ' ') . ' UEC', 'sample_count' => count($values), ]; } function index_vanilla_uex_fetch_estimates(array $names, int $sampleLimit = 10): array { $results = []; $uniqueNames = []; foreach ($names as $name) { $name = trim((string) $name); if ($name === '' || isset($uniqueNames[$name])) { continue; } $uniqueNames[$name] = $name; } if ($uniqueNames === []) { return $results; } $multiHandle = curl_multi_init(); $handles = []; $userAgent = 'Mozilla/5.0 (compatible; FlatLogicVanillaDb/1.0; +https://uexcorp.space/)'; foreach ($uniqueNames as $name) { $url = 'https://uexcorp.space/search?q=' . rawurlencode($name); $handle = curl_init(); curl_setopt_array($handle, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_CONNECTTIMEOUT => 4, CURLOPT_TIMEOUT => 8, CURLOPT_USERAGENT => $userAgent, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_HTTPHEADER => [ 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language: fr-FR,fr;q=0.9,en;q=0.8', 'Cache-Control: no-cache', ], ]); curl_multi_add_handle($multiHandle, $handle); $handles[$name] = $handle; } $running = null; do { $status = curl_multi_exec($multiHandle, $running); if ($running) { curl_multi_select($multiHandle, 1.0); } } while ($running && $status === CURLM_OK); foreach ($handles as $name => $handle) { $error = curl_error($handle); $httpCode = (int) curl_getinfo($handle, CURLINFO_RESPONSE_CODE); $body = (string) curl_multi_getcontent($handle); if ($error !== '' || $httpCode < 200 || $httpCode >= 300 || trim($body) === '') { $results[$name] = [ 'has_estimate' => false, 'average' => null, 'formatted' => 'Indisponible', 'sample_count' => 0, 'error' => true, ]; } else { $results[$name] = index_vanilla_uex_parse_estimate_from_html($body, $name, $sampleLimit); $results[$name]['error'] = false; } curl_multi_remove_handle($multiHandle, $handle); curl_close($handle); } curl_multi_close($multiHandle); return $results; } auth_start_session(); auth_bootstrap(); $session_cl_auth_user = isset($_SESSION['user']) ? (string) $_SESSION['user'] : ''; $session_cl_auth_right = isset($_SESSION['role']) ? (string) $_SESSION['role'] : ''; $is_authenticated = $session_cl_auth_user !== ''; $has_member_access = $is_authenticated && in_array($session_cl_auth_right, ['member', 'admin'], true); $has_vanilla_db_access = $is_authenticated && in_array($session_cl_auth_right, ['member', 'moderator', 'admin'], true); if (isset($_GET['ajax']) && (string) $_GET['ajax'] === 'vanilla-price-estimates') { header('Content-Type: application/json; charset=UTF-8'); if (!$has_vanilla_db_access) { http_response_code(403); echo json_encode([ 'ok' => false, 'message' => 'Accès refusé.', 'estimates' => new stdClass(), ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } $requestedNames = $_GET['names'] ?? []; if (!is_array($requestedNames)) { $requestedNames = [$requestedNames]; } $requestedNames = array_slice(array_values(array_filter(array_map('strval', $requestedNames), static fn ($name): bool => trim($name) !== '')), 0, 10); $estimates = index_vanilla_uex_fetch_estimates($requestedNames, 10); echo json_encode([ 'ok' => true, 'estimates' => $estimates, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } $scan_reference_rows = []; $scan_reference_max_occurrence = 0; $scan_reference_error = null; $ship_preset_rows = []; $ship_preset_manufacturers = []; $ship_preset_error = null; $item_custom_public_rows = []; $item_custom_public_types = []; $item_custom_public_error = null; $vanilla_db_rows = []; $vanilla_db_error = null; $vanilla_db_search = ''; $vanilla_db_per_page = 10; $vanilla_db_total_rows = 0; $vanilla_db_total_pages = 1; $vanilla_db_current_page = 1; $vanilla_db_result_start = 0; $vanilla_db_result_end = 0; $vanilla_db_base_query = ['open_modal' => 'vanilla-db']; $vanilla_db_reset_url = 'index.php?open_modal=vanilla-db'; $should_open_vanilla_db_modal = false; try { $db = db(); $stmt_scan_reference = $db->query( "SELECT o.cl_scobjs_id, o.cl_scobjs_name, o.cl_scobjs_rarity, m.cl_scmining_scan_value, m.cl_scmining_max_occurrence, m.cl_scmining_can_manual, m.cl_scmining_can_land, m.cl_scmining_can_space FROM tbl_scmining m INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = m.cl_scmining_obj_id ORDER BY CASE UPPER(COALESCE(o.cl_scobjs_rarity, '')) WHEN 'L' THEN 1 WHEN 'E' THEN 2 WHEN 'R' THEN 3 WHEN 'U' THEN 4 WHEN 'C' THEN 5 ELSE 6 END, o.cl_scobjs_name ASC" ); foreach ($stmt_scan_reference->fetchAll() as $row) { $occurrence_count = max(1, (int) ($row['cl_scmining_max_occurrence'] ?? 1)); $scan_value = (int) ($row['cl_scmining_scan_value'] ?? 0); $recovery_modes = []; if (!empty($row['cl_scmining_can_manual'])) { $recovery_modes[] = 'Manuel'; } if (!empty($row['cl_scmining_can_land'])) { $recovery_modes[] = 'Terrestre'; } if (!empty($row['cl_scmining_can_space'])) { $recovery_modes[] = 'Spatial'; } $scan_steps = []; for ($i = 1; $i <= $occurrence_count; $i++) { $scan_steps[] = $scan_value * $i; } $scan_reference_rows[] = [ 'id' => (string) ($row['cl_scobjs_id'] ?? ''), 'name' => (string) ($row['cl_scobjs_name'] ?? ''), 'rarity' => index_scan_normalize_rarity($row['cl_scobjs_rarity'] ?? ''), 'rarity_label' => index_scan_rarity_label($row['cl_scobjs_rarity'] ?? ''), 'rarity_class' => index_scan_rarity_class($row['cl_scobjs_rarity'] ?? ''), 'recovery_modes' => $recovery_modes, 'scan_steps' => $scan_steps, 'max_occurrence' => $occurrence_count, ]; $scan_reference_max_occurrence = max($scan_reference_max_occurrence, $occurrence_count); } } catch (Throwable $e) { $scan_reference_error = 'Impossible de charger le tableau des signatures de scan pour le moment.'; } if ($has_member_access) { try { if (!isset($db) || !($db instanceof PDO)) { $db = db(); } $stmt_ship_presets = $db->query( "SELECT cl_scpreset_id, cl_scpreset_name, cl_scpreset_manufacturer, cl_scpreset_description, cl_scpreset_link, cl_scpreset_creator FROM tbl_scpreset ORDER BY cl_scpreset_manufacturer ASC, cl_scpreset_name ASC" ); foreach ($stmt_ship_presets->fetchAll() as $row) { $ship_name = trim((string) ($row['cl_scpreset_name'] ?? '')) ?: 'Vaisseau inconnu'; $manufacturer = trim((string) ($row['cl_scpreset_manufacturer'] ?? '')) ?: 'Manufacture inconnue'; $manufacturer_key = function_exists('mb_strtolower') ? mb_strtolower($manufacturer, 'UTF-8') : strtolower($manufacturer); $ship_preset_manufacturers[$manufacturer_key] = $manufacturer; $ship_preset_rows[] = [ 'id' => (string) ($row['cl_scpreset_id'] ?? ''), 'name' => $ship_name, 'manufacturer' => $manufacturer, 'creator' => trim((string) ($row['cl_scpreset_creator'] ?? '')) ?: 'Inconnu', 'description' => trim((string) ($row['cl_scpreset_description'] ?? '')) ?: 'Aucune description disponible pour ce preset.', 'link' => trim((string) ($row['cl_scpreset_link'] ?? '')), ]; } natcasesort($ship_preset_manufacturers); $ship_preset_manufacturers = array_values($ship_preset_manufacturers); } catch (Throwable $e) { $ship_preset_error = 'Impossible de charger les presets de vaisseaux pour le moment.'; } } if ($has_member_access) { try { if (!isset($db) || !($db instanceof PDO)) { $db = db(); } $stmt_item_custom_public = $db->query( "SELECT c.cl_scitemcustom_id, o.cl_scobjs_name, o.cl_scobjs_uuid, o.cl_scobjs_type, o.cl_scobjs_subtype, COALESCE(NULLIF(TRIM(a.cl_auth_user), ''), 'Inconnu') AS creator_name, cs.cl_scitemcustomstat_id, cs.cl_scitemcustomstat_sign, cs.cl_scitemcustomstat_value, st.cl_scstatsitem_name, st.cl_scstatsitem_unit FROM tbl_scitemcustom c INNER JOIN tbl_scobjs o ON o.cl_scobjs_id = c.cl_scitemcustom_obj_id LEFT JOIN tbl_auth a ON a.cl_auth_id = c.cl_scitemcustom_owner_auth_id LEFT JOIN tbl_scitemcustomstat cs ON cs.cl_scitemcustomstat_itemcustom_id = c.cl_scitemcustom_id LEFT JOIN tbl_scstatsitem st ON st.cl_scstatsitem_id = cs.cl_scitemcustomstat_stat_id WHERE c.cl_scitemcustom_owner_auth_id IS NOT NULL ORDER BY o.cl_scobjs_name ASC, creator_name ASC, c.cl_scitemcustom_id ASC, st.cl_scstatsitem_name ASC, cs.cl_scitemcustomstat_id ASC" ); $grouped_item_custom_public = []; foreach ($stmt_item_custom_public->fetchAll() as $row) { $item_id = (int) ($row['cl_scitemcustom_id'] ?? 0); if ($item_id <= 0) { continue; } if (!isset($grouped_item_custom_public[$item_id])) { $name = trim((string) ($row['cl_scobjs_name'] ?? '')) ?: 'Objet inconnu'; $creator = trim((string) ($row['creator_name'] ?? '')) ?: 'Inconnu'; $type = trim((string) ($row['cl_scobjs_type'] ?? '')); $subtype = trim((string) ($row['cl_scobjs_subtype'] ?? '')); $uuid = trim((string) ($row['cl_scobjs_uuid'] ?? '')); $grouped_item_custom_public[$item_id] = [ 'id' => $item_id, 'name' => $name, 'creator' => $creator, 'type' => $type, 'subtype' => $subtype, 'uuid' => $uuid, 'stats' => [], 'search_parts' => [$name, $creator, $type, $subtype, $uuid], ]; } if (!empty($row['cl_scitemcustomstat_id'])) { $stat_name = trim((string) ($row['cl_scstatsitem_name'] ?? '')) ?: 'Stat inconnue'; $stat_sign = trim((string) ($row['cl_scitemcustomstat_sign'] ?? '')); $stat_value_raw = $row['cl_scitemcustomstat_value'] ?? 0; $stat_unit = trim((string) ($row['cl_scstatsitem_unit'] ?? '')); $stat_preview = index_itemcustom_stat_preview($stat_sign, $stat_value_raw, $stat_unit); $grouped_item_custom_public[$item_id]['stats'][] = [ 'name' => $stat_name, 'preview' => $stat_preview, ]; $grouped_item_custom_public[$item_id]['search_parts'][] = $stat_name; $grouped_item_custom_public[$item_id]['search_parts'][] = $stat_preview; } } $item_custom_public_types_lookup = []; foreach ($grouped_item_custom_public as $item_custom_public_row) { $item_custom_public_row['search'] = trim(implode(' ', array_filter($item_custom_public_row['search_parts'], static function ($value) { return trim((string) $value) !== ''; }))); unset($item_custom_public_row['search_parts']); $item_custom_public_rows[] = $item_custom_public_row; $item_custom_public_type_label = $item_custom_public_row['type'] !== '' ? $item_custom_public_row['type'] : 'Type inconnu'; $item_custom_public_type_key = strtolower($item_custom_public_type_label); if (!isset($item_custom_public_types_lookup[$item_custom_public_type_key])) { $item_custom_public_types_lookup[$item_custom_public_type_key] = $item_custom_public_type_label; } } natcasesort($item_custom_public_types_lookup); $item_custom_public_types = array_values($item_custom_public_types_lookup); } catch (Throwable $e) { $item_custom_public_error = 'Impossible de charger les objets Item Custom pour le moment.'; } } if ($has_vanilla_db_access) { $vanilla_db_search = trim((string) ($_GET['vanilla_search'] ?? '')); $vanilla_db_current_page = max(1, (int) ($_GET['vanilla_page'] ?? 1)); $should_open_vanilla_db_modal = ( (isset($_GET['open_modal']) && (string) $_GET['open_modal'] === 'vanilla-db') || $vanilla_db_search !== '' || isset($_GET['vanilla_page']) ); $vanilla_db_base_query = ['open_modal' => 'vanilla-db']; if ($vanilla_db_search !== '') { $vanilla_db_base_query['vanilla_search'] = $vanilla_db_search; } $vanilla_db_reset_url = 'index.php?' . http_build_query(['open_modal' => 'vanilla-db']); try { if (!isset($db) || !($db instanceof PDO)) { $db = db(); } $vanilla_db_where_sql = ''; $vanilla_db_bindings = []; if ($vanilla_db_search !== '') { $vanilla_db_where_sql = " WHERE ( cl_scobjs_name LIKE :vanilla_search OR cl_scobjs_type LIKE :vanilla_search OR cl_scobjs_subtype LIKE :vanilla_search OR cl_scobjs_uuid LIKE :vanilla_search OR cl_scobjs_rarity LIKE :vanilla_search OR cl_scobjs_description LIKE :vanilla_search )"; $vanilla_db_bindings[':vanilla_search'] = '%' . $vanilla_db_search . '%'; } $stmt_vanilla_db_count = $db->prepare( "SELECT COUNT(*) FROM tbl_scobjs" . $vanilla_db_where_sql ); foreach ($vanilla_db_bindings as $bindingName => $bindingValue) { $stmt_vanilla_db_count->bindValue($bindingName, $bindingValue, PDO::PARAM_STR); } $stmt_vanilla_db_count->execute(); $vanilla_db_total_rows = (int) $stmt_vanilla_db_count->fetchColumn(); $vanilla_db_total_pages = max(1, (int) ceil($vanilla_db_total_rows / $vanilla_db_per_page)); $vanilla_db_current_page = min($vanilla_db_current_page, $vanilla_db_total_pages); $vanilla_db_offset = ($vanilla_db_current_page - 1) * $vanilla_db_per_page; $stmt_vanilla_db = $db->prepare( "SELECT cl_scobjs_id, cl_scobjs_name, cl_scobjs_type, cl_scobjs_subtype, cl_scobjs_uuid, cl_scobjs_rarity, cl_scobjs_description FROM tbl_scobjs" . $vanilla_db_where_sql . " ORDER BY cl_scobjs_id DESC LIMIT :vanilla_limit OFFSET :vanilla_offset" ); foreach ($vanilla_db_bindings as $bindingName => $bindingValue) { $stmt_vanilla_db->bindValue($bindingName, $bindingValue, PDO::PARAM_STR); } $stmt_vanilla_db->bindValue(':vanilla_limit', $vanilla_db_per_page, PDO::PARAM_INT); $stmt_vanilla_db->bindValue(':vanilla_offset', $vanilla_db_offset, PDO::PARAM_INT); $stmt_vanilla_db->execute(); foreach ($stmt_vanilla_db->fetchAll() as $row) { $name = trim((string) ($row['cl_scobjs_name'] ?? '')) ?: 'Objet inconnu'; $type = trim((string) ($row['cl_scobjs_type'] ?? '')) ?: '—'; $subtype = trim((string) ($row['cl_scobjs_subtype'] ?? '')) ?: '—'; $uuid = trim((string) ($row['cl_scobjs_uuid'] ?? '')) ?: '—'; $rarity = index_scan_normalize_rarity($row['cl_scobjs_rarity'] ?? ''); $description = trim((string) ($row['cl_scobjs_description'] ?? '')); $vanilla_db_rows[] = [ 'id' => (int) ($row['cl_scobjs_id'] ?? 0), 'name' => $name, 'type' => $type, 'subtype' => $subtype, 'uuid' => $uuid, 'image_url' => $uuid !== '—' ? 'https://cstone.space/uifimages/' . rawurlencode($uuid) . '.png' : null, 'rarity' => $rarity !== '' ? $rarity : '—', 'rarity_label' => $rarity !== '' ? index_scan_rarity_label($rarity) : 'Non définie', 'rarity_class' => index_scan_rarity_class($rarity), 'description_html' => index_vanilla_description_html($description), ]; } if ($vanilla_db_total_rows > 0) { $vanilla_db_result_start = $vanilla_db_offset + 1; $vanilla_db_result_end = $vanilla_db_offset + count($vanilla_db_rows); } } catch (Throwable $e) { $vanilla_db_error = 'Impossible de charger la base des objets pour le moment.'; } } ?> Rapid Emergency & Action Combat Team / Star Citizen
id="accountPanel"> > > Administration Déconnexion

Rapid Emergency & Action Combat Team

Fondée pour combattre la criminalité extrême à travers l’Univers, la R.E.A.C.T. est un label opérationnel indépendant. Nous unissons des pilotes dévoués de tous horizons pour neutraliser les menaces là où la loi fait défaut.

—————— La R.E.A.C.T. n’est pas une organisation, mais un standard tactique ——————

C’est une initiative inter-organisations conçue pour les joueurs qui partagent la même vision : protéger les citoyens et les PNJs des entités hostiles. Porter l’insigne R.E.A.C.T. ne signifie pas quitter votre organisation ; cela signifie rejoindre un réseau d'intervention rapide.