70 lines
2 KiB
PHP
70 lines
2 KiB
PHP
<?php
|
|
|
|
final class GeocodeService
|
|
{
|
|
/**
|
|
* Géocodage via Nominatim (OpenStreetMap)
|
|
* Retour: ['lat'=>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'] ?? ''),
|
|
];
|
|
}
|
|
}
|