float, 'lng'=>float, 'display_name'=>string] ou null * * IMPORTANT: * - Respecte le fair use : pas de spam (cache côté DB chez toi, et TTL) * - User-Agent explicite */ public static function geocode(string $query): ?array { $query = trim($query); if ($query === '') { return null; } // Nominatim conseille d'envoyer un UA + un contact $email = getenv('GEOCODER_EMAIL') ?: 'contact@localhost'; $ua = 'TwixRefuge/1.0 (geocoding; contact: ' . $email . ')'; $url = 'https://nominatim.openstreetmap.org/search?format=jsonv2&limit=1&addressdetails=0&q=' . rawurlencode($query); $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => 12, CURLOPT_CONNECTTIMEOUT => 6, CURLOPT_HTTPHEADER => ['User-Agent: ' . $ua, 'Accept: application/json'], CURLOPT_ENCODING => '', // gzip/br si dispo ]); $body = curl_exec($ch); if ($body === false) { curl_close($ch); return null; } $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($status < 200 || $status >= 300) { return null; } $json = json_decode($body, true); if (!is_array($json) || empty($json[0])) { return null; } $item = $json[0]; $lat = isset($item['lat']) ? (float) $item['lat'] : null; $lng = isset($item['lon']) ? (float) $item['lon'] : null; if ($lat === null || $lng === null) { return null; } return [ 'lat' => $lat, 'lng' => $lng, 'display_name' => (string) ($item['display_name'] ?? ''), ]; } }