"$errstr in $errfile on line $errline"]); exit; } set_error_handler("errorHandler"); /** * Stock Symbol Checker API * Usage: ?q=SYMBOL (max 6 chars) or ?q=ISIN (8+ chars) */ $input = isset($_GET['q']) ? strtoupper(trim($_GET['q'])) : ''; if (empty($input)) { echo json_encode(['error' => 'No input provided. Use ?q=SYMBOL or ?q=ISIN']); exit; } // Read stocks.json from same directory $jsonFile = __DIR__ . '/stocks.json'; if (!file_exists($jsonFile)) { echo json_encode(['error' => 'stocks.json not found', 'path' => $jsonFile]); exit; } $stocks = json_decode(file_get_contents($jsonFile), true); if (!$stocks) { echo json_encode(['error' => 'stocks.json is invalid']); exit; } // Determine input type $isSymbol = strlen($input) <= 6; $isIsin = strlen($input) >= 8; $found = null; $isinToCheck = null; $inJson = false; if ($isSymbol) { // Search for symbol in stocks.json foreach ($stocks as $item) { if (strtoupper($item['stock']) === $input) { $found = $item; $inJson = true; $isinToCheck = $found['isin'] ?? null; break; } } if (!$found) { echo json_encode([ 'status' => 'not_found', 'symbol' => $input, 'injson' => false, 'gettex' => 'no' ]); exit; } } elseif ($isIsin) { // Input is ISIN $isinToCheck = $input; // Check if this ISIN exists in stocks.json foreach ($stocks as $item) { if (!empty($item['isin']) && strtoupper($item['isin']) === $input) { $found = $item; $inJson = true; break; } } // Check Gettex for the ISIN $inGettex = isIsinInGettex($isinToCheck); if ($inJson && $found) { echo json_encode([ 'status' => 'found_in_json', 'symbol' => $found['stock'], 'isin' => $found['isin'], 'injson' => true, 'gettex' => $inGettex ? 'yes' : 'no', 'price' => $found['price'], 'currency' => $found['currency'], 'date' => $found['date'], 'exchange_market' => $found['exchange_market'], 'depot' => $found['depot'] ?? null, 'nrbght' => $found['nrbght'] ?? null ]); } else { echo json_encode([ 'status' => 'isin_checked', 'submitted_isin' => $input, 'injson' => false, 'gettex' => $inGettex ? 'yes' : 'no', 'note' => 'ISIN checked against Gettex data' ]); } exit; } else { echo json_encode([ 'error' => 'Ambiguous input length', 'input' => $input, 'length' => strlen($input), 'note' => 'Symbols should be max 6 chars, ISIN should be 8+ chars' ]); exit; } // Symbol found in JSON $inGettex = false; if (!empty($isinToCheck)) { $inGettex = isIsinInGettex($isinToCheck); } echo json_encode([ 'status' => 'found', 'symbol' => $found['stock'], 'injson' => true, 'isin' => $found['isin'] ?? null, 'gettex' => $inGettex ? 'yes' : 'no', 'price' => $found['price'], 'currency' => $found['currency'], 'date' => $found['date'], 'exchange_market' => $found['exchange_market'], 'depot' => $found['depot'] ?? null, 'nrbght' => $found['nrbght'] ?? null ]); /** * Check if ISIN exists in Gettex data using cURL (iframe-safe) */ function isIsinInGettex($isin) { $cacheFile = __DIR__ . '/gettex_cache.json'; $cacheExpiry = 3600; // 1 hour cache // Check cache if (file_exists($cacheFile)) { $cache = json_decode(file_get_contents($cacheFile), true); if ($cache && isset($cache['timestamp']) && (time() - $cache['timestamp']) < $cacheExpiry) { if (isset($cache['data'][$isin])) { return $cache['data'][$isin]; } } } // --- Weekend check (German GMT = UTC+1/UTC+2) --- $now = new DateTime('now', new DateTimeZone('Europe/Berlin')); $dayOfWeek = (int)$now->format('N'); // 1=Mon, 7=Sun $isWeekend = ($dayOfWeek >= 6); // Saturday or Sunday if ($isWeekend) { // Use the weekend URL directly $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://alcea-wisteria.de/z_files/trading/exchangeplatform/gettex.csv.gz'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $gzContent = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode === 200 && $gzContent) { $csvContent = gzdecode($gzContent); if ($csvContent && strpos($csvContent, $isin) !== false) { // Cache the positive result $cacheData = ['timestamp' => time(), 'data' => [$isin => true]]; file_put_contents($cacheFile, json_encode($cacheData)); return true; } elseif ($csvContent) { // Extract all ISINs from weekend CSV for caching preg_match_all('/[A-Z]{2}[A-Z0-9]{9}[0-9]/', $csvContent, $isinMatches); $allIsins = []; if (!empty($isinMatches[0])) { foreach ($isinMatches[0] as $foundIsin) { $allIsins[$foundIsin] = true; } } // Cache all found ISINs + negative result for this ISIN $cacheData = ['timestamp' => time(), 'data' => $allIsins + [$isin => false]]; file_put_contents($cacheFile, json_encode($cacheData)); return false; } } // If weekend fetch fails, return false (no fallback to weekday data) return false; } // --- Normal weekday logic (unchanged) --- // Fetch Gettex page with cURL (works in iframes) $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://www.gettex.de/handel/delayed-data/posttrade-data/'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'); curl_setopt($ch, CURLOPT_TIMEOUT, 15); $html = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode !== 200 || !$html) { return false; } // Extract CSV file URLs preg_match_all('/href="(https:\/\/erdk\.bayerische-boerse\.de:8000\/delayed-data\/[^"]+\.csv\.gz)"/', $html, $matches); if (empty($matches[1])) { return false; } $allIsins = []; foreach ($matches[1] as $url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0'); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $gzContent = curl_exec($ch); curl_close($ch); if (!$gzContent) continue; $csvContent = gzdecode($gzContent); if (!$csvContent) continue; // Check if our ISIN exists in this CSV if (strpos($csvContent, $isin) !== false) { // Cache the positive result $cacheData = ['timestamp' => time(), 'data' => [$isin => true]]; file_put_contents($cacheFile, json_encode($cacheData)); return true; } // Extract all ISINs for caching preg_match_all('/[A-Z]{2}[A-Z0-9]{9}[0-9]/', $csvContent, $isinMatches); if (!empty($isinMatches[0])) { foreach ($isinMatches[0] as $foundIsin) { $allIsins[$foundIsin] = true; } } } // Cache all found ISINs + negative result for this ISIN $cacheData = ['timestamp' => time(), 'data' => $allIsins + [$isin => false]]; file_put_contents($cacheFile, json_encode($cacheData)); return false; } ?>