/* ===== Webcam 2025 – Page Détail ===== - Même thèmes / menus / langues que l’index - Météo DB (table meteo), pas de weatherwidget.io - Carte Leaflet + RainViewer centrée sur la webcam - Horloge locale (en fonction du pays) - Compteurs visites (site + webcam) - Description “IA-like”, nav précédent/suivant (sous les compteurs) */ error_reporting(E_ALL); ini_set('display_errors','1'); // UTF-8 + CSP (1 seule ligne — pas de newline dans le header) header('Content-Type: text/html; charset=UTF-8'); // Helpers function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } function cleanText($s){ $s = (string)$s; $s = html_entity_decode($s, ENT_QUOTES | ENT_HTML5, 'UTF-8'); if (class_exists('Normalizer')) $s = Normalizer::normalize($s, Normalizer::FORM_C); return $s; } function hx($s){ return h(cleanText($s)); } function degToCardinal16($deg){ $dirs = ["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"]; $i = (int)round(((($deg % 360)+360)%360)/22.5) % 16; return $dirs[$i]; } // ==== I18N (début de traduction des textes visuels) ==== $allowed = ['fr','en','es','de','it','pt','ru','zh-CN','ja','nl','sv','pl','ar','hi','tr','id']; $ogLocales = [ 'fr'=>'fr_FR','en'=>'en_US','es'=>'es_ES','de'=>'de_DE','it'=>'it_IT','pt'=>'pt_PT', 'ru'=>'ru_RU','zh-CN'=>'zh_CN','ja'=>'ja_JP','nl'=>'nl_NL','sv'=>'sv_SE','pl'=>'pl_PL', 'ar'=>'ar_AR','hi'=>'hi_IN','tr'=>'tr_TR','id'=>'id_ID' ]; $TR = [ 'alt' => [ 'fr'=>'Alt.','en'=>'Alt.','es'=>'Alt.','de'=>'Höhe','it'=>'Alt.','pt'=>'Alt.','ru'=>'Выс.','zh-CN'=>'海拔','ja'=>'標高','nl'=>'Hoogte','sv'=>'Alt.','pl'=>'Wys.', 'ar'=>'الارتفاع','hi'=>'ऊंचाई','tr'=>'Rak.','id'=>'Ketinggian' ], 'timelapse_yesterday'=>[ 'fr'=>"Timelapse d’hier",'en'=>"Yesterday’s timelapse",'es'=>"Time-lapse de ayer",'de'=>"Zeitraffer von gestern", 'it'=>"Time-lapse di ieri",'pt'=>"Time-lapse de ontem",'ru'=>"Таймлапс за вчера",'zh-CN'=>"昨日延时摄影", 'ja'=>"昨日のタイムラプス",'nl'=>"Time-lapse van gisteren",'sv'=>"Gårdagens timelapse",'pl'=>"Wczorajszy timelapse", 'ar'=>"الفاصل الزمني لأمس",'hi'=>"कल का टाइम-लैप्स",'tr'=>"Dünün time-lapse'ı",'id'=>"Time-lapse kemarin" ], 'kpi_updated'=>[ 'fr'=>'Dernière mise à jour','en'=>'Last update','es'=>'Última actualización','de'=>'Letztes Update','it'=>'Ultimo aggiornamento', 'pt'=>'Última atualização','ru'=>'Обновлено','zh-CN'=>'最近更新','ja'=>'最終更新','nl'=>'Laatste update','sv'=>'Senast uppdaterad','pl'=>'Ostatnia aktualizacja', 'ar'=>'آخر تحديث','hi'=>'अंतिम अपडेट','tr'=>'Son güncelleme','id'=>'Pembaruan terakhir' ], 'pressure'=>[ 'fr'=>'Pression','en'=>'Pressure','es'=>'Presión','de'=>'Luftdruck','it'=>'Pressione','pt'=>'Pressão','ru'=>'Давление','zh-CN'=>'气压','ja'=>'気圧','nl'=>'Luchtdruk','sv'=>'Lufttryck','pl'=>'Ciśnienie', 'ar'=>'الضغط','hi'=>'दाब','tr'=>'Basınç','id'=>'Tekanan' ], 'humidity'=>[ 'fr'=>'Humidité','en'=>'Humidity','es'=>'Humedad','de'=>'Luftfeuchte','it'=>'Umidità','pt'=>'Humidade','ru'=>'Влажность','zh-CN'=>'湿度','ja'=>'湿度','nl'=>'Vochtigheid','sv'=>'Luftfuktighet','pl'=>'Wilgotność', 'ar'=>'الرطوبة','hi'=>'नमी','tr'=>'Nem','id'=>'Kelembapan' ], 'weather'=>[ 'fr'=>'Temps','en'=>'Weather','es'=>'Tiempo','de'=>'Wetter','it'=>'Meteo','pt'=>'Tempo','ru'=>'Погода','zh-CN'=>'天气','ja'=>'天気','nl'=>'Weer','sv'=>'Väder','pl'=>'Pogoda', 'ar'=>'الطقس','hi'=>'मौसम','tr'=>'Hava','id'=>'Cuaca' ], 'temperature'=>[ 'fr'=>'Température','en'=>'Temperature','es'=>'Temperatura','de'=>'Temperatur','it'=>'Temperatura','pt'=>'Temperatura','ru'=>'Температура','zh-CN'=>'气温','ja'=>'気温','nl'=>'Temperatuur','sv'=>'Temperatur','pl'=>'Temperatura', 'ar'=>'الحرارة','hi'=>'तापमान','tr'=>'Sıcaklık','id'=>'Suhu' ], 'wind'=>[ 'fr'=>'Vent','en'=>'Wind','es'=>'Viento','de'=>'Wind','it'=>'Vento','pt'=>'Vento','ru'=>'Ветер','zh-CN'=>'风','ja'=>'風','nl'=>'Wind','sv'=>'Vind','pl'=>'Wiatr', 'ar'=>'الرياح','hi'=>'हवा','tr'=>'Rüzgâr','id'=>'Angin' ], 'direction'=>[ 'fr'=>'Dir.','en'=>'Dir.','es'=>'Dir.','de'=>'Richt.','it'=>'Dir.','pt'=>'Dir.','ru'=>'Напр.','zh-CN'=>'风向','ja'=>'方位','nl'=>'Richting','sv'=>'Rikt.','pl'=>'Kier.', 'ar'=>'الاتجاه','hi'=>'दिशा','tr'=>'Yön','id'=>'Arah' ], 'gusts'=>[ 'fr'=>'Rafales','en'=>'Gusts','es'=>'Rachas','de'=>'Böen','it'=>'Raffiche','pt'=>'Rajadas','ru'=>'Порывы','zh-CN'=>'阵风','ja'=>'突風','nl'=>'Vlagen','sv'=>'Byar','pl'=>'Porywy', 'ar'=>'هبات','hi'=>'झोंके','tr'=>'Rüzgâr esintileri','id'=>'Hembusan' ], 'coords'=>[ 'fr'=>'Coordonnées','en'=>'Coordinates','es'=>'Coordenadas','de'=>'Koordinaten','it'=>'Coordinate','pt'=>'Coordenadas','ru'=>'Координаты','zh-CN'=>'坐标','ja'=>'座標','nl'=>'Coördinaten','sv'=>'Koordinater','pl'=>'Współrzędne', 'ar'=>'الإحداثيات','hi'=>'निर्देशांक','tr'=>'Koordinatlar','id'=>'Koordinat' ], 'map_radar'=>[ 'fr'=>'Carte & radar','en'=>'Map & radar','es'=>'Mapa y radar','de'=>'Karte & Radar','it'=>'Mappa e radar','pt'=>'Mapa e radar','ru'=>'Карта и радар','zh-CN'=>'地图与雷达','ja'=>'地図とレーダー','nl'=>'Kaart & radar','sv'=>'Karta & radar','pl'=>'Mapa i radar', 'ar'=>'الخريطة والرادار','hi'=>'मानचित्र व रडार','tr'=>'Harita ve radar','id'=>'Peta & radar' ], 'local_time'=>[ 'fr'=>'Heure locale','en'=>'Local time','es'=>'Hora local','de'=>'Ortszeit','it'=>'Ora locale','pt'=>'Hora local','ru'=>'Местное время','zh-CN'=>'当地时间','ja'=>'現地時刻','nl'=>'Lokale tijd','sv'=>'Lokal tid','pl'=>'Czas lokalny', 'ar'=>'الوقت المحلي','hi'=>'स्थानीय समय','tr'=>'Yerel saat','id'=>'Waktu lokal' ], 'nearby'=>[ 'fr'=>'Webcams proches','en'=>'Nearby webcams','es'=>'Cámaras cercanas','de'=>'Nahe Webcams','it'=>'Webcam vicine','pt'=>'Webcams próximas','ru'=>'Ближайшие камеры','zh-CN'=>'附近摄像头','ja'=>'付近のウェブカメラ','nl'=>'Webcams in de buurt','sv'=>'Närliggande kameror','pl'=>'Kamery w pobliżu', 'ar'=>'كاميرات قريبة','hi'=>'पास की वेबकैम','tr'=>'Yakındaki kameralar','id'=>'Kamera terdekat' ], 'none_nearby'=>[ 'fr'=>'Aucune à proximité.','en'=>'None nearby.','es'=>'Ninguna cercana.','de'=>'Keine in der Nähe.','it'=>'Nessuna nelle vicinanze.','pt'=>'Nenhuma por perto.','ru'=>'Нет поблизости.','zh-CN'=>'附近暂无。','ja'=>'近くにありません。','nl'=>'Geen in de buurt.','sv'=>'Inga i närheten.','pl'=>'Brak w pobliżu.', 'ar'=>'لا توجد قريبة.','hi'=>'आस-पास कोई नहीं।','tr'=>'Yakında yok.','id'=>'Tidak ada di dekat sini.' ], 'nav'=>[ 'fr'=>'Navigation :','en'=>'Navigation:','es'=>'Navegación:','de'=>'Navigation:','it'=>'Navigazione:','pt'=>'Navegação:','ru'=>'Навигация:','zh-CN'=>'导航:','ja'=>'ナビゲーション:','nl'=>'Navigatie:','sv'=>'Navigering:','pl'=>'Nawigacja:', 'ar'=>'التنقل:','hi'=>'नेविगेशन:','tr'=>'Gezinme:','id'=>'Navigasi:' ], 'prev'=>[ 'fr'=>'Précédent','en'=>'Previous','es'=>'Anterior','de'=>'Vorherige','it'=>'Precedente','pt'=>'Anterior','ru'=>'Предыдущая','zh-CN'=>'上一条','ja'=>'前へ','nl'=>'Vorige','sv'=>'Föregående','pl'=>'Poprzednia', 'ar'=>'السابق','hi'=>'पिछला','tr'=>'Önceki','id'=>'Sebelumnya' ], 'next'=>[ 'fr'=>'Suivant','en'=>'Next','es'=>'Siguiente','de'=>'Nächste','it'=>'Successiva','pt'=>'Seguinte','ru'=>'Следующая','zh-CN'=>'下一条','ja'=>'次へ','nl'=>'Volgende','sv'=>'Nästa','pl'=>'Następna', 'ar'=>'التالي','hi'=>'अगला','tr'=>'Sonraki','id'=>'Berikutnya' ], 'thanks'=>[ 'fr'=>'Merci à','en'=>'Thanks to','es'=>'Gracias a','de'=>'Danke an','it'=>'Grazie a','pt'=>'Obrigado a','ru'=>'Спасибо','zh-CN'=>'感谢','ja'=>'ありがとう','nl'=>'Dank aan','sv'=>'Tack till','pl'=>'Dziękujemy', 'ar'=>'شكرًا لـ','hi'=>'धन्यवाद','tr'=>'Teşekkürler','id'=>'Terima kasih kepada' ], 'webcam_visits'=>[ 'fr'=>'Webcam : %s visites','en'=>'Webcam: %s visits','es'=>'Webcam: %s visitas','de'=>'Webcam: %s Aufrufe','it'=>'Webcam: %s visite','pt'=>'Webcam: %s visitas','ru'=>'Камера: %s просмотров','zh-CN'=>'摄像头:%s 次访问','ja'=>'Webカメラ:%s 回','nl'=>'Webcam: %s bezoeken','sv'=>'Webbkamera: %s visningar','pl'=>'Kamera: %s wizyt', 'ar'=>'الكاميرا: %s زيارة','hi'=>'वेबकैम: %s विज़िट','tr'=>'Kamera: %s ziyaret','id'=>'Webcam: %s kunjungan' ], 'site_visits'=>[ 'fr'=>'Site : %s lives visualisés','en'=>'Site: %s lives viewed','es'=>'Sitio: %s directos vistos','de'=>'Seite: %s Lives angesehen','it'=>'Sito: %s live visualizzati','pt'=>'Site: %s lives vistos','ru'=>'Сайт: %s просмотров трансляций','zh-CN'=>'全站:观看 %s 次直播','ja'=>'サイト合計:%s 回ライブ視聴','nl'=>'Site: %s lives bekeken','sv'=>'Sajt: %s lives visade','pl'=>'Witryna: %s wyświetleń live', 'ar'=>'الموقع: تمت مشاهدة %s بثًا مباشراً','hi'=>'साइट: %s लाइव देखे गए','tr'=>'Site: %s canlı izlendi','id'=>'Situs: %s live ditonton' ], 'contact_title'=>[ 'fr'=>'Contact','en'=>'Contact','es'=>'Contacto','de'=>'Kontakt','it'=>'Contatto','pt'=>'Contacto','ru'=>'Контакты','zh-CN'=>'联系','ja'=>'お問い合わせ','nl'=>'Contact','sv'=>'Kontakt','pl'=>'Kontakt', 'ar'=>'اتصال','hi'=>'संपर्क','tr'=>'İletişim','id'=>'Kontak' ], 'contact_text'=>[ 'fr'=>'Pour toute question, partenariat ou support, écrivez-nous :', 'en'=>'For any question, partnership or support, write to us:', 'es'=>'Para cualquier consulta, asociación o soporte, escríbenos:', 'de'=>'Für Fragen, Partnerschaften oder Support schreiben Sie uns:', 'it'=>'Per domande, partnership o supporto, scrivici:', 'pt'=>'Para dúvidas, parcerias ou suporte, escreva-nos:', 'ru'=>'По вопросам, партнёрству или поддержке пишите нам:', 'zh-CN'=>'如有问题、合作或支持,请写信至:', 'ja'=>'ご質問・提携・サポートは、こちらへ:', 'nl'=>'Voor vragen, partnerschap of support, mail ons:', 'sv'=>'För frågor, partnerskap eller support, skriv till oss:', 'pl'=>'W sprawie pytań, współpracy lub wsparcia napisz do nas:', 'ar'=>'لأي سؤال أو شراكة أو دعم، راسلنا:', 'hi'=>'किसी भी प्रश्न, साझेदारी या सहायता हेतु हमें लिखें:', 'tr'=>'Sorularınız, ortaklık veya destek için bize yazın:', 'id'=>'Pertanyaan, kemitraan, atau dukungan: tulis kepada kami:' ], 'order_title'=>[ 'fr'=>'Commander votre webcam','en'=>'Order your webcam','es'=>'Encargar su webcam','de'=>'Webcam bestellen','it'=>'Ordina la tua webcam','pt'=>'Encomendar a sua webcam','ru'=>'Заказать веб-камеру','zh-CN'=>'订购您的摄像头','ja'=>'Webカメラを導入','nl'=>'Bestel uw webcam','sv'=>'Beställ din webbkamera','pl'=>'Zamów swoją kamerę', 'ar'=>'اطلب كاميرا الويب الخاصة بك','hi'=>'अपना वेबकैम ऑर्डर करें','tr'=>'Web kameranızı sipariş edin','id'=>'Pesan webcam Anda' ], 'order_text'=>[ 'fr'=>'VISION-ENVIRONNEMENT installe et diffuse des webcams touristiques professionnelles en HD/4K. Équipez votre ville, station ou entreprise avec une solution clé en main.', 'en'=>'VISION-ENVIRONNEMENT installs and streams professional HD/4K tourist webcams. Equip your city, resort or business with a turnkey solution.', 'es'=>'VISION-ENVIRONNEMENT instala y emite webcams turísticas profesionales en HD/4K. Equipe su ciudad, estación o empresa con una solución llave en mano.', 'de'=>'VISION-ENVIRONNEMENT installiert und streamt professionelle HD/4K-Touristen-Webcams. Rüsten Sie Stadt, Skigebiet oder Unternehmen schlüsselfertig aus.', 'it'=>'VISION-ENVIRONNEMENT installa e diffonde webcam turistiche professionali in HD/4K. Soluzione chiavi in mano per città, stazioni e aziende.', 'pt'=>'A VISION-ENVIRONNEMENT instala e transmite webcams turísticas profissionais em HD/4K. Equipe sua cidade, estação ou empresa com solução turnkey.', 'ru'=>'VISION-ENVIRONNEMENT устанавливает и транслирует профессиональные HD/4K туристические веб-камеры. Комплексное решение для города, курорта или бизнеса.', 'zh-CN'=>'VISION-ENVIRONNEMENT 提供专业 HD/4K 旅游摄像头安装与直播,一站式解决方案服务城市/景区/企业。', 'ja'=>'VISION-ENVIRONNEMENT は観光向けプロ用 HD/4K ウェブカメラを設置・配信します。自治体・施設・企業向けのワンストップ導入。', 'nl'=>'VISION-ENVIRONNEMENT installeert en streamt professionele HD/4K toeristische webcams. Turnkey oplossing voor stad, resort of bedrijf.', 'sv'=>'VISION-ENVIRONNEMENT installerar och sänder professionella HD/4K-webbkameror. Nyckelfärdig lösning för stad, anläggning eller företag.', 'pl'=>'VISION-ENVIRONNEMENT instaluje i transmituje profesjonalne kamery HD/4K. Rozwiązanie „pod klucz” dla miast, ośrodków i firm.', 'ar'=>'VISION-ENVIRONNEMENT تقوم بتركيب وبث كاميرات سياحية احترافية بدقة HD/4K. حل متكامل لمدينتك أو منتجعك أو شركتك.', 'hi'=>'VISION-ENVIRONNEMENT पेशेवर HD/4K पर्यटन वेबकैम स्थापित और स्ट्रीम करता है। शहर, स्टेशन या व्यवसाय के लिए टर्नकी समाधान।', 'tr'=>'VISION-ENVIRONNEMENT, profesyonel HD/4K turistik web kameraları kurar ve yayınlar. Şehriniz, tesisiniz veya işletmeniz için anahtar teslim çözüm.', 'id'=>'VISION-ENVIRONNEMENT memasang dan menyiarkan webcam wisata profesional HD/4K. Solusi turnkey untuk kota, resor, atau bisnis Anda.' ], 'order_cta'=>[ 'fr'=>'Demander un devis','en'=>'Get a quote','es'=>'Solicitar presupuesto','de'=>'Angebot anfordern','it'=>'Richiedi preventivo','pt'=>'Pedir orçamento','ru'=>'Запросить смету','zh-CN'=>'获取报价','ja'=>'見積もり依頼','nl'=>'Offerte aanvragen','sv'=>'Begär offert','pl'=>'Poproś o wycenę', 'ar'=>'اطلب عرض سعر','hi'=>'कोटेशन मांगें','tr'=>'Teklif isteyin','id'=>'Minta penawaran' ], 'live_text'=>[ 'fr'=>"à travers une vue en direct qui capte l’atmosphère du moment. Panoramas, météo et mouvements du ciel : cette caméra vous plonge au cœur du paysage. Idéale pour préparer vos sorties, suivre les conditions ou simplement vous évader quelques instants.", 'en'=>"through a live view that captures the atmosphere of the moment. Panoramas, weather, and sky movements — this camera immerses you in the heart of the landscape. Perfect for planning your outings, checking conditions, or simply escaping for a moment.", 'es'=>"a través de una vista en directo que capta la atmósfera del momento. Panoramas, clima y movimientos del cielo: esta cámara te sumerge en el corazón del paisaje. Ideal para preparar tus salidas, seguir las condiciones o simplemente evadirte unos instantes.", 'de'=>"durch eine Live-Ansicht, die die Atmosphäre des Augenblicks einfängt. Panoramen, Wetter und Himmelsbewegungen – diese Kamera versetzt Sie mitten in die Landschaft. Ideal, um Ihre Ausflüge zu planen, die Bedingungen zu verfolgen oder einfach kurz zu entfliehen.", 'it'=>"attraverso una vista dal vivo che cattura l’atmosfera del momento. Panorami, meteo e movimenti del cielo: questa telecamera ti immerge nel cuore del paesaggio. Ideale per preparare le tue uscite, seguire le condizioni o semplicemente evadere per un momento.", 'pt'=>"através de uma vista ao vivo que capta a atmosfera do momento. Panoramas, clima e movimentos do céu: esta câmera mergulha você no coração da paisagem. Ideal para planejar seus passeios, acompanhar as condições ou simplesmente se desligar por um momento.", 'ru'=>"в прямом эфире, передающем атмосферу момента. Панорамы, погода и движение облаков — эта камера погружает вас в самое сердце пейзажа. Идеально, чтобы спланировать прогулку, следить за погодой или просто ненадолго отвлечься.", 'zh-CN'=>"通过实时画面捕捉当下的氛围。全景、天气与天空的变化——这台摄像机将您带入景色的核心。非常适合规划出行、了解天气状况或短暂放松心情。", 'ja'=>"その瞬間の雰囲気を捉えるライブ映像を通して。パノラマ、天気、空の動き——このカメラは風景の中心へとあなたを誘います。外出の計画、気象の確認、あるいは少しの癒しに最適です。", 'nl'=>"via een livebeeld dat de sfeer van het moment vastlegt. Panorama’s, weer en bewegingen van de lucht – deze camera dompelt je onder in het hart van het landschap. Perfect om je uitstapjes te plannen, de omstandigheden te volgen of gewoon even te ontsnappen.", 'sv'=>"genom en direktsänd vy som fångar stämningen i ögonblicket. Panoraman, väder och himlens rörelser – denna kamera tar dig rakt in i landskapet. Perfekt för att planera utflykter, följa vädret eller bara koppla av en stund.", 'pl'=>"poprzez podgląd na żywo, który oddaje atmosferę chwili. Panoramy, pogoda i ruchy nieba – ta kamera przenosi Cię w samo serce krajobrazu. Idealna, by zaplanować wyjście, sprawdzić warunki lub po prostu na chwilę się odprężyć.", 'ar'=>"من خلال عرض مباشر يلتقط أجواء اللحظة. مناظر بانورامية، طقس وحركة السماء — هذه الكاميرا تغمرك في قلب المشهد. مثالية للتخطيط للخروج، متابعة الظروف أو فقط للهرب قليلاً.", 'hi'=>"उस लाइव दृश्य के माध्यम से जो पल के वातावरण को कैद करता है। पैनोरमा, मौसम और आकाश की गतियाँ—यह कैमरा आपको दृश्य के केंद्र में ले जाता है। सैर की योजना, स्थिति जाँचने या थोड़ी देर सुकून के लिए उत्तम।", 'tr'=>"Anın atmosferini yakalayan canlı bir görüntüyle. Panoramalar, hava durumu ve gökyüzünün hareketleri — bu kamera sizi manzaranın kalbine götürür. Gezi planlamak, koşulları izlemek ya da biraz kaçış için ideal.", 'id'=>"Lewat tayangan langsung yang menangkap suasana saat ini. Panorama, cuaca, dan gerak langit — kamera ini membawa Anda ke inti lanskap. Sempurna untuk merencanakan waktu keluar, memantau kondisi, atau sekadar melepas penat." ], 'discover'=>[ 'fr'=>"Découvrez",'en'=>"Discover",'es'=>"Descubre",'de'=>"Entdecken Sie",'it'=>"Scopri",'pt'=>"Descubra", 'ru'=>"Откройте",'zh-CN'=>"探索",'ja'=>"発見する",'nl'=>"Ontdek",'sv'=>"Upptäck",'pl'=>"Odkryj", 'ar'=>"اكتشف",'hi'=>"खोजिए",'tr'=>"Keşfedin",'id'=>"Temukan" ], ]; function t($key, $fallback=''){ global $TR, $currentLang; if (isset($TR[$key][$currentLang])) return $TR[$key][$currentLang]; if (isset($TR[$key]['fr'])) return $TR[$key]['fr']; return $fallback!=='' ? $fallback : $key; } // ==== Connexion DB ==== @include __DIR__ . '/connect.php'; if (!isset($connect) || !($connect instanceof mysqli)) { http_response_code(500); echo "ERREUR DB
Connexion DB absente. Vérifie livecams/connect.php
"; exit; } @mysqli_set_charset($connect,'utf8mb4'); // ==== Menus (déjà traduits comme l'index) ==== $menuLabel = [ 'map' => ['fr'=>'Carte','en'=>'Map','es'=>'Mapa','de'=>'Karte','it'=>'Mappa','pt'=>'Mapa','ru'=>'Карта','zh-CN'=>'地图','ja'=>'地図','nl'=>'Kaart','sv'=>'Karta','pl'=>'Mapa'], 'search' => ['fr'=>'Recherche','en'=>'Search','es'=>'Buscar','de'=>'Suche','it'=>'Ricerca','pt'=>'Pesquisar','ru'=>'Поиск','zh-CN'=>'搜索','ja'=>'検索','nl'=>'Zoeken','sv'=>'Sök','pl'=>'Szukaj'], 'contact'=> ['fr'=>'Contact','en'=>'Contact','es'=>'Contacto','de'=>'Kontakt','it'=>'Contatto','pt'=>'Contacto','ru'=>'Контакты','zh-CN'=>'联系','ja'=>'お問い合わせ','nl'=>'Contact','sv'=>'Kontakt','pl'=>'Kontakt'], 'order' => ['fr'=>'Commander votre webcam','en'=>'Order your webcam','es'=>'Encargar su webcam','de'=>'Webcam bestellen','it'=>'Ordina la tua webcam','pt'=>'Encomendar a sua webcam','ru'=>'Заказать вашу веб-камеру','zh-CN'=>'订购您的摄像头','ja'=>'Webカメラを注文','nl'=>'Bestel uw webcam','sv'=>'Beställ din webbkamera','pl'=>'Zamów swoją kamerę'], ]; function tMenu(string $key, string $fallback=''){ global $menuLabel, $currentLang; $val = $menuLabel[$key][$currentLang] ?? $fallback ?? ($menuLabel[$key]['fr'] ?? $key); return h($val); } // ==== Langue / thème (même logique que l’index) ==== $host = $_SERVER['HTTP_HOST'] ?? ''; $baseDomain = preg_replace('~^www\.~','', $host); $currentLang = 'fr'; // défaut $manual = isset($_COOKIE['ve_lang_manual']) && $_COOKIE['ve_lang_manual']==='1'; // ?lang= prioritaire if (!empty($_GET['lang']) && in_array($_GET['lang'],$allowed,true)) { $currentLang = $_GET['lang']; @setcookie('ve_lang_manual','1', time()+31536000, '/', $baseDomain ? ".$baseDomain" : ''); foreach (['', ".$baseDomain"] as $dom) { @setcookie('googtrans','', time()-3600, '/', $dom?:'', false); } } else { $cookieLang = null; if (!empty($_COOKIE['googtrans']) && preg_match('~^/fr/([a-z]{2}(?:-[A-Z]{2})?)$~', $_COOKIE['googtrans'], $m)) { $cookieLang = $m[1]; if (!in_array($cookieLang, $allowed, true)) $cookieLang = null; } if ($manual && $cookieLang && $cookieLang!=='fr') $currentLang = $cookieLang; } // ==== Paramètre : slug ==== $slug = isset($_GET['webcam']) ? trim((string)$_GET['webcam']) : ''; if ($slug==='') { http_response_code(400); echo "Paramètre manquant

Paramètre ?webcam= requis.

"; exit; } // ==== Webcam ciblée ==== (ajout: structure pour crédit) $cam = null; $sql = "SELECT id, nom, live, image, timelapse, pays, region, latitude, longitude, altitude, client, lienclient, structure, V3, statut, weatherio FROM webcam WHERE statut=1 AND id=? LIMIT 1"; if ($st = mysqli_prepare($connect,$sql)) { mysqli_stmt_bind_param($st,'s',$slug); mysqli_stmt_execute($st); $res = mysqli_stmt_get_result($st); $cam = mysqli_fetch_assoc($res); mysqli_free_result($res); mysqli_stmt_close($st); } if (!$cam) { http_response_code(404); echo "Webcam introuvable

Aucune webcam active pour l’identifiant ".h($slug).".

"; exit; } $cam['nom'] = cleanText($cam['nom'] ?? ''); $cam['pays'] = cleanText($cam['pays'] ?? ''); $cam['region'] = cleanText($cam['region'] ?? ''); $cam['structure'] = cleanText($cam['structure'] ?? ''); $cam['client'] = cleanText($cam['client'] ?? ''); $lat = is_numeric($cam['latitude']??null) ? (float)$cam['latitude'] : null; $lon = is_numeric($cam['longitude']??null) ? (float)$cam['longitude'] : null; $name = $cam['nom']; // ex: "Montpinçon" $reg = $cam['region']; // ex: "Normandie" // ==== Fuseau / Heure locale — version fine (IANA + cas particuliers) function _norm_country($s){ $s = trim((string)$s); $s = html_entity_decode($s, ENT_QUOTES | ENT_HTML5, 'UTF-8'); if (function_exists('iconv')) $s = @iconv('UTF-8','ASCII//TRANSLIT//IGNORE',$s); $s = strtolower(preg_replace('~[^a-z]+~',' ', $s)); $s = trim(str_replace([' metropolitaine',' metropolitan',' mainland'], '', $s)); return $s; } function guess_tz_by_country_robust($pays){ $p = _norm_country($pays); $map = [ // Europe “mono-fuseau” 'france'=>'Europe/Paris','monaco'=>'Europe/Monaco','andorre'=>'Europe/Andorra', 'espagne'=>'Europe/Madrid','spain'=>'Europe/Madrid', 'portugal'=>'Europe/Lisbon','suisse'=>'Europe/Zurich','switzerland'=>'Europe/Zurich', 'belgique'=>'Europe/Brussels','belgium'=>'Europe/Brussels', 'italie'=>'Europe/Rome','italy'=>'Europe/Rome','allemagne'=>'Europe/Berlin','germany'=>'Europe/Berlin', 'pays bas'=>'Europe/Amsterdam','netherlands'=>'Europe/Amsterdam', 'royaume uni'=>'Europe/London','united kingdom'=>'Europe/London','uk'=>'Europe/London','irlande'=>'Europe/Dublin','ireland'=>'Europe/Dublin', 'norvege'=>'Europe/Oslo','suede'=>'Europe/Stockholm','finlande'=>'Europe/Helsinki','danemark'=>'Europe/Copenhagen', 'autriche'=>'Europe/Vienna','pologne'=>'Europe/Warsaw','grece'=>'Europe/Athens','tchequie'=>'Europe/Prague','czechia'=>'Europe/Prague', 'islande'=>'Atlantic/Reykjavik','iceland'=>'Atlantic/Reykjavik', // Maghreb 'maroc'=>'Africa/Casablanca','tunisie'=>'Africa/Tunis','algerie'=>'Africa/Algiers', // MO / Afrique 'turquie'=>'Europe/Istanbul','afrique du sud'=>'Africa/Johannesburg', 'emirats arabes unis'=>'Asia/Dubai','uae'=>'Asia/Dubai', // Asie “mono” 'inde'=>'Asia/Kolkata','india'=>'Asia/Kolkata','chine'=>'Asia/Shanghai','china'=>'Asia/Shanghai', 'japon'=>'Asia/Tokyo','japan'=>'Asia/Tokyo','coree du sud'=>'Asia/Seoul','south korea'=>'Asia/Seoul', // Océanie “mono” 'nouvelle zelande'=>'Pacific/Auckland','new zealand'=>'Pacific/Auckland', ]; return $map[$p] ?? null; } function guess_tz_by_latlon_fine($lat,$lon,$pays=''){ $p = _norm_country($pays); // -------- FR Outre-mer -------- // Guadeloupe if ($lat>15.7 && $lat<16.6 && $lon>-62.0 && $lon<-61.1) return 'America/Guadeloupe'; // Martinique if ($lat>14.3 && $lat<14.9 && $lon>-61.3 && $lon<-60.8) return 'America/Martinique'; // Guyane if ($lat>2 && $lat<6.5 && $lon>-54.7 && $lon<-51.5) return 'America/Cayenne'; // Réunion if ($lat>-21.5 && $lat>-22.0 && $lon>55.1 && $lon<55.9) return 'Indian/Reunion'; // Mayotte if ($lat>-13.1 && $lat>-13.1 && $lon>45.0 && $lon<45.4) return 'Indian/Mayotte'; // Polynésie française (simplifié : Tahiti) if ($lat>-23.5 && $lat<-14 && $lon<-146 && $lon>-155) return 'Pacific/Tahiti'; // Nouvelle-Calédonie if ($lat>-23.5 && $lat<-19.5 && $lon>163 && $lon<168.5) return 'Pacific/Noumea'; // Saint-Pierre-et-Miquelon if ($lat>46.6 && $lat<47.2 && $lon>-56.6 && $lon<-56.1) return 'America/St_Pierre'; // Wallis-et-Futuna if ($lat>-14.5 && $lat<-13.0 && $lon>-177.5 && $lon<-175.5) return 'Pacific/Wallis'; // Saint-Barthélemy if ($lat>17.85 && $lat<18.0 && $lon>-62.9 && $lon<-62.75) return 'America/St_Barthelemy'; // Saint-Martin (partie française) if ($lat>18.03 && $lat<18.15 && $lon>-63.15 && $lon<-62.95) return 'America/Marigot'; // -------- Espagne îles / enclaves -------- // Canaries if ($lat>27 && $lat<30 && $lon>-18.5 && $lon<-13.0) return 'Atlantic/Canary'; // Ceuta / Melilla (en Afrique) if ($lat>35.2 && $lat<35.9 && $lon>-5.7 && $lon<-2.7) return 'Africa/Ceuta'; // -------- Portugal îles -------- // Açores if ($lat>36 && $lat<41 && $lon>-31.5 && $lon<-24.5) return 'Atlantic/Azores'; // Madère if ($lat>32.2 && $lat<33.3 && $lon>-17.4 && $lon<-15.7) return 'Atlantic/Madeira'; // -------- USA & Canada -------- // Hawaï if ($lat>18 && $lat<23.5 && $lon<-154 && $lon>-161.5) return 'Pacific/Honolulu'; // Alaska — Aléoutiennes à l'ouest if ($p==='etats unis' || $p==='etatsunis' || $p==='usa' || $p==='united states' || $p==='us'){ if ($lon < -169.5) return 'America/Adak'; // Aleutian if ($lon <= -127) return 'America/Anchorage'; // Alaska (reste) // Arizona (approx bbox, ignore Navajo DST) if ($lat>31 && $lat<37 && $lon>-115 && $lon<-109) return 'America/Phoenix'; // Côtes / bandes classiques if ($lon <= -114) return 'America/Los_Angeles'; elseif ($lon <= -103) return 'America/Denver'; elseif ($lon <= -90 ) return 'America/Chicago'; elseif ($lon <= -66 ) return 'America/New_York'; else return 'America/New_York'; } if ($p==='canada'){ // Saskatchewan (pas de DST) if ($lat>49 && $lat<60 && $lon>-110.1 && $lon<-101.0) return 'America/Regina'; if ($lon <= -114) return 'America/Vancouver'; elseif ($lon <= -103) return 'America/Edmonton'; elseif ($lon <= -90 ) return 'America/Winnipeg'; elseif ($lon <= -66 ) return 'America/Toronto'; else return 'America/Halifax'; } // -------- Mexique -------- if ($p==='mexique' || $p==='mexico'){ // Basse-Californie (Pacifique nord-ouest) if ($lon < -112) return 'America/Tijuana'; // Quintana Roo (Cancún) — EST sans DST if ($lat>18 && $lat<22.5 && $lon>-88.9 && $lon<-86.5) return 'America/Cancun'; // Pacifique ou Centre if ($lon < -86) return 'America/Mazatlan'; return 'America/Mexico_City'; } // -------- Brésil -------- if ($p==='bresil' || $p==='brazil'){ // Fernando de Noronha if ($lat>-4.0 && $lat<-3.7 && $lon>-32.6 && $lon<-32.2) return 'America/Noronha'; if ($lon < -67) return 'America/Rio_Branco'; // Acre (-5) if ($lon < -54) return 'America/Manaus'; // Amazonie occidentale (-4) if ($lon < -44) return 'America/Cuiaba'; // Centre-Ouest (-4/-3) return 'America/Sao_Paulo'; // Sudeste/Sud (-3) } // -------- Chili -------- if ($p==='chili' || $p==='chile'){ if ($lon < -100) return 'Pacific/Easter'; // Région de Magallanes (Punta Arenas) ~ très sud if ($lat < -48) return 'America/Punta_Arenas'; return 'America/Santiago'; } // -------- Russie -------- if ($p==='russie' || $p==='russia'){ // Kaliningrad if ($lat>54 && $lat<56.3 && $lon>19 && $lon<23.5) return 'Europe/Kaliningrad'; if ($lon < 50) return 'Europe/Moscow'; elseif ($lon < 60) return 'Europe/Samara'; elseif ($lon < 75) return 'Asia/Yekaterinburg'; elseif ($lon < 90) return 'Asia/Omsk'; elseif ($lon < 105) return 'Asia/Krasnoyarsk'; elseif ($lon < 120) return 'Asia/Irkutsk'; elseif ($lon < 135) return 'Asia/Yakutsk'; elseif ($lon < 150) return 'Asia/Vladivostok'; elseif ($lon < 165) return 'Asia/Magadan'; else return 'Asia/Kamchatka'; } // -------- Australie -------- if ($p==='australie' || $p==='australia'){ if ($lon < 129) return 'Australia/Perth'; // WA if ($lon < 141) return ($lat < -26) ? 'Australia/Adelaide' : 'Australia/Darwin'; return ($lon > 150 || $lat < -28) ? 'Australia/Sydney' : 'Australia/Brisbane'; } // -------- Indonésie (3 grands fuseaux) -------- if ($p==='indonesie' || $p==='indonesia'){ if ($lon < 114) return 'Asia/Jakarta'; // Ouest (Sumatra/Java) elseif ($lon < 129) return 'Asia/Makassar'; // Centre (Borneo/Célèbes) else return 'Asia/Jayapura'; // Est (Papouasie) } // -------- Europe de l’Ouest si pays vide mais bbox plausible -------- if ($lat > 34 && $lat < 62 && $lon > -10.5 && $lon < 30) { if ($lat>41 && $lat<51.7 && $lon>-5.7 && $lon<9.9) return 'Europe/Paris'; // France if ($lat>35 && $lat<44.8 && $lon>-9.9 && $lon<4.7) return 'Europe/Madrid'; // Espagne if ($lat>36 && $lat<43.8 && $lon>-9.6 && $lon<-6.0) return 'Europe/Lisbon'; // Portugal (continent) } return null; } $tzId = null; if ($lat !== null && $lon !== null) { $tzId = guess_tz_by_latlon_fine($lat,$lon,$cam['pays']); } if (!$tzId) { $tzId = guess_tz_by_country_robust($cam['pays']); } if (!$tzId && $lon !== null){ // Ultime recours: fuseau fixe par longitude (sans DST) $offsetH = (int)round($lon / 15); $tzId = 'Etc/GMT'.($offsetH===0 ? '' : ($offsetH>0?'-'.abs($offsetH):'+'.abs($offsetH))); } if (!$tzId) $tzId = 'UTC'; try { $dt = new DateTime('now', new DateTimeZone($tzId)); $local_ts_ms = ((int)$dt->format('U')) * 1000; } catch(Throwable $e){ $tzId = 'UTC'; $dt = new DateTime('now', new DateTimeZone('UTC')); $local_ts_ms = ((int)$dt->format('U')) * 1000; } // ==== Météo (dernier enregistrement) $meteo = null; $sqlm = "SELECT horodatage, conditions, description, temperature, vent, rafales, pression, humidity, temp_min, temp_max, ventdir FROM meteo WHERE id=? ORDER BY horodatage DESC LIMIT 1"; if ($stm = mysqli_prepare($connect,$sqlm)) { mysqli_stmt_bind_param($stm,'s',$slug); mysqli_stmt_execute($stm); $resm = mysqli_stmt_get_result($stm); $meteo = mysqli_fetch_assoc($resm); mysqli_free_result($resm); mysqli_stmt_close($stm); } $windKmh = $meteo ? (int)round(((float)$meteo['vent']) * 3.6) : null; $gustKmh = $meteo ? (int)round(((float)$meteo['rafales']) * 3.6) : null; $windDeg = $meteo && isset($meteo['ventdir']) ? (int)round((float)$meteo['ventdir']) : 0; $windDir = $meteo && isset($meteo['ventdir']) ? degToCardinal16((float)$meteo['ventdir']) : null; // ==== Webcams proches $near = []; if ($lat!==null && $lon!==null) { $q = "SELECT id, nom, pays, region, latitude, longitude FROM webcam WHERE statut=1 AND id<>? LIMIT 1500"; if ($stn = mysqli_prepare($connect,$q)) { mysqli_stmt_bind_param($stn,'s',$slug); mysqli_stmt_execute($stn); $rs = mysqli_stmt_get_result($stn); $seen = []; while($r = mysqli_fetch_assoc($rs)){ $rid = (string)$r['id']; if (isset($seen[$rid])) continue; if (!is_numeric($r['latitude']??null) || !is_numeric($r['longitude']??null)) continue; $rlat=(float)$r['latitude']; $rlon=(float)$r['longitude']; $dlat = deg2rad($rlat - $lat); $dlon = deg2rad($rlon - $lon); $a = sin($dlat/2)**2 + cos(deg2rad($lat))*cos(deg2rad($rlat))*sin($dlon/2)**2; $c = 2 * atan2(sqrt($a), sqrt(1-$a)); $km = 6371 * $c; $seen[$rid]=true; $near[] = [ 'id'=>$rid, 'nom'=>cleanText($r['nom']??''), 'pays'=>cleanText($r['pays']??''), 'region'=>cleanText($r['region']??''), 'km'=>$km, ]; } mysqli_free_result($rs); mysqli_stmt_close($stn); } usort($near, fn($a,$b)=> $a['km']<=>$b['km']); $near = array_slice($near, 0, 10); } // ==== Prev / Next (par ordre d'id) $prev = $next = null; if ($st = mysqli_prepare($connect, "SELECT id, nom FROM webcam WHERE statut=1 AND id < ? ORDER BY id DESC LIMIT 1")) { mysqli_stmt_bind_param($st,'s',$slug); mysqli_stmt_execute($st); $r = mysqli_stmt_get_result($st); $prev = mysqli_fetch_assoc($r) ?: null; mysqli_free_result($r); mysqli_stmt_close($st); } if ($st = mysqli_prepare($connect, "SELECT id, nom FROM webcam WHERE statut=1 AND id > ? ORDER BY id ASC LIMIT 1")) { mysqli_stmt_bind_param($st,'s',$slug); mysqli_stmt_execute($st); $r = mysqli_stmt_get_result($st); $next = mysqli_fetch_assoc($r) ?: null; mysqli_free_result($r); mysqli_stmt_close($st); } // ==== Compteurs $visites_webcam = null; $visites_total = null; $counterId = preg_replace('~[^a-zA-Z0-9_\-]~','', (string)$cam['id']); $camCounterUrl = "https://s1.vision-environnement.com/webcams/player/compteurs/compteur_{$counterId}.txt"; $totalCounterUrl = "https://s1.vision-environnement.com/webcams/player/compteurs/compteur_total.txt"; $ctx = stream_context_create(['http'=>['timeout'=>2]]); if ($counter = @file_get_contents($camCounterUrl, false, $ctx)) { $n = (int)preg_replace('~\D~','', $counter); $visites_webcam = number_format($n, 0, ' ', ' '); } if ($total = @file_get_contents($totalCounterUrl, false, $ctx)) { $n = (int)preg_replace('~\D~','', $total); $visites_total = number_format($n, 0, ' ', ' '); } // ==== SEO multilingue + méta localisés function metaTitle($lang, $cam){ $name=$cam['nom']; $reg=$cam['region']; $cty=$cam['pays']; $site='VISION-ENVIRONNEMENT'; $map = [ 'fr'=>"Webcam {$name} – {$reg} – {$cty} · {$site}", 'en'=>"{$name} webcam – {$reg} – {$cty} · {$site}", 'es'=>"Webcam {$name} – {$reg} – {$cty} · {$site}", 'de'=>"{$name} Webcam – {$reg} – {$cty} · {$site}", 'it'=>"Webcam {$name} – {$reg} – {$cty} · {$site}", 'pt'=>"Webcam {$name} – {$reg} – {$cty} · {$site}", 'ru'=>"Веб-камера {$name} – {$reg} – {$cty} · {$site}", 'zh-CN'=>"{$name} 实况摄像头 – {$reg} – {$cty} · {$site}", 'ja'=>"{$name} ライブカメラ – {$reg} – {$cty} · {$site}", 'nl'=>"{$name} webcam – {$reg} – {$cty} · {$site}", 'sv'=>"{$name} webbkamera – {$reg} – {$cty} · {$site}", 'pl'=>"Kamera {$name} – {$reg} – {$cty} · {$site}", ]; return $map[$lang] ?? $map['fr']; } function metaDesc($lang, $cam){ $name=$cam['nom']; $reg=$cam['region']; $cty=$cam['pays']; $alt=(int)$cam['altitude']; $map = [ 'fr'=>"Live HD/4K de {$name} ({$reg}) – {$cty} • Alt. {$alt} m. Radar pluie, météo et webcams à proximité.", 'en'=>"Live HD/4K from {$name} ({$reg}) – {$cty} • Alt. {$alt} m. Rain radar, weather and nearby webcams.", 'es'=>"Directo HD/4K de {$name} ({$reg}) – {$cty} • Alt. {$alt} m. Radar de lluvia, tiempo y webcams cercanas.", 'de'=>"HD/4K-Live aus {$name} ({$reg}) – {$cty} • Höhe {$alt} m. Regenradar, Wetter und nahe Webcams.", 'it'=>"Live HD/4K da {$name} ({$reg}) – {$cty} • Quota {$alt} m. Radar pioggia, meteo e webcam vicine.", 'pt'=>"Ao vivo HD/4K de {$name} ({$reg}) – {$cty} • Alt. {$alt} m. Radar de chuva, meteo e webcams próximas.", 'ru'=>"HD/4K-трансляция {$name} ({$reg}) – {$cty} • выс. {$alt} м. Осадки, погода и ближайшие камеры.", 'zh-CN'=>"{$name} ({$reg}) – {$cty} 实况 HD/4K • 海拔 {$alt} m。降雨雷达、天气与附近摄像头。", 'ja'=>"{$name}({$reg})– {$cty} の HD/4K ライブ • 標高 {$alt} m。雨レーダー・天気・周辺カメラ。", 'nl'=>"HD/4K-live uit {$name} ({$reg}) – {$cty} • Hoogte {$alt} m. Regenradar, weer en webcams in de buurt.", 'sv'=>"HD/4K-live från {$name} ({$reg}) – {$cty} • Höjd {$alt} m. Regnradar, väder och närliggande kameror.", 'pl'=>"Transmisja HD/4K z {$name} ({$reg}) – {$cty} • Wys. {$alt} m. Radar opadów, pogoda i kamery w pobliżu.", ]; return $map[$lang] ?? $map['fr']; } $siteName = 'VISION-ENVIRONNEMENT'; $title = metaTitle($currentLang, $cam); $desc = metaDesc($currentLang, $cam); $imgOg = $cam['image'] ?: "https://www.vision-environnement.com/livecams/img/desktop-logo.png"; $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS']!=='off') ? 'https' : 'http'; $hostFull = $_SERVER['HTTP_HOST'] ?? 'www.vision-environnement.com'; $baseUrl = "$scheme://$hostFull{$_SERVER['PHP_SELF']}?webcam=".rawurlencode($cam['id']); if ($currentLang!=='fr') $baseUrl .= '&lang='.rawurlencode($currentLang); function langUrl($lang, $id){ $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS']!=='off') ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? 'www.vision-environnement.com'; $u = "$scheme://$host{$_SERVER['PHP_SELF']}?webcam=".rawurlencode($id); if ($lang!=='fr') $u .= '&lang='.rawurlencode($lang); return $u; } ?>