From 3565a8808588708da2561bf67ee4f8ff79113884 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 19 Apr 2026 19:44:04 +0000 Subject: [PATCH] V1.4.1 --- index-en.php | 409 +++++++++++++++++++++++++++++++++++++++++++++++++-- index.php | 392 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 791 insertions(+), 10 deletions(-) diff --git a/index-en.php b/index-en.php index 86a862e..30927b6 100644 --- a/index-en.php +++ b/index-en.php @@ -69,6 +69,233 @@ function index_vanilla_description_html(?string $description): string 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(); @@ -78,6 +305,34 @@ $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' => 'Access denied.', + '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; @@ -97,7 +352,7 @@ $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'; +$vanilla_db_reset_url = 'index-en.php?open_modal=vanilla-db'; $should_open_vanilla_db_modal = false; try { @@ -302,7 +557,7 @@ if ($has_vanilla_db_access) { 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']); + $vanilla_db_reset_url = 'index-en.php?' . http_build_query(['open_modal' => 'vanilla-db']); try { if (!isset($db) || !($db instanceof PDO)) { @@ -1421,6 +1676,28 @@ if ($has_vanilla_db_access) { word-break: break-all; } + .vanilla-db-card-estimate { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-size: 0.95em; + color: rgba(255, 224, 138, 0.92); + word-break: normal; + } + + .vanilla-db-card-estimate strong { + font-weight: 600; + color: rgba(255, 236, 178, 0.98); + } + + .vanilla-db-card-estimate-value.is-loading { + color: rgba(255, 255, 255, 0.62); + } + + .vanilla-db-card-estimate-value.is-unavailable { + color: rgba(255, 180, 180, 0.88); + } + .vanilla-db-card-uuid { display: inline-block; font-size: 0.76em; @@ -1961,7 +2238,7 @@ if ($has_vanilla_db_access) {

-
+
@@ -1995,6 +2272,7 @@ if ($has_vanilla_db_access) {

+

UEX estimate: Loading...

UUID : UUID : —

@@ -2022,14 +2300,14 @@ if ($has_vanilla_db_access) {
1): ?> - « + « - + 1): ?> - 1 + 1 2): ?> @@ -2040,7 +2318,7 @@ if ($has_vanilla_db_access) { - + @@ -2049,14 +2327,14 @@ if ($has_vanilla_db_access) { - + - + - » + »
@@ -2422,6 +2700,117 @@ if ($has_vanilla_db_access) { })(); + + + +