Координаты по текстовому адресу в PHP: Geocoding API и запись lat/lng в таблицу
Задача и поля в БД
В каталогах и справочниках магазинов часто хранят текстовый адрес, а для карты на сайте нужны числовые координаты. Типичная схема в пользовательской таблице (b_hlbd_* или обычный InnoDB‑таблица рядом с проектом): колонки lat и lng типа числа с достаточной точностью, плюс флаг вроде is_loc_checked, чтобы помечать строки уже обработанные геокодером (включая неудачные попытки, чтобы не долбить API бесконечно).
Старый приём и почему его обновили
Раньше можно было дергать http://maps.googleapis.com/maps/api/geocode/json без ключа на простых задачах. Сейчас для продакшена нужен включённый Google Geocoding API, ограниченный ключ (по referrer или IP вашего cron‑хоста) и только HTTPS. Квота и платные вызовы — обычная эксплуатация: лимиты и биллинг смотреть в Google Cloud Console; в ответах по-прежнему бывает статус вроде OVER_QUERY_LIMIT — его стоит логировать и останавливать пакет, а не падать немым die().
Каркас клиента без жёсткой привязки к БД
Ниже — выделенная функция, которая по адресу возвращает широту и долготу или null. Имя ключа и URL взяты параметрами, чтобы ключ не светился в репозитории: передайте его из переменной окружения, .settings.php или параметра модуля на стороне «1С‑Битрикс».
declare(strict_types=1);
/**
* @return array{lat: float, lng: float}|null
*/
function resolve_address_geocode(string $address, string $apiKey): ?array
{
$base = 'https://maps.googleapis.com/maps/api/geocode/json';
$query = http_build_query([
'address' => $address,
'key' => $apiKey,
'language' => 'ru',
], '', '&', PHP_QUERY_RFC3986);
$ch = curl_init($base . '?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 8,
CURLOPT_TIMEOUT => 20,
]);
$payload = curl_exec($ch);
if ($payload === false) {
return null;
}
curl_close($ch);
$decoded = json_decode($payload, true);
if (!is_array($decoded) || !isset($decoded['status'])) {
return null;
}
if ($decoded['status'] === 'OVER_QUERY_LIMIT') {
throw new RuntimeException('Geocoding quota exceeded');
}
if ($decoded['status'] !== 'OK' || empty($decoded['results'][0]['geometry']['location'])) {
return null;
}
$loc = $decoded['results'][0]['geometry']['location'];
if (!isset($loc['lat'], $loc['lng'])) {
return null;
}
return [
'lat' => (float) $loc['lat'],
'lng' => (float) $loc['lng'],
];
}Цикл по «необработанным» точкам и запись координат
После успешного геокодирования сохраняйте числа как числа — без addslashes над вещественными литералами сниппетом из двухтысячных. В PDO или соединении Битрикса используйте плейсхолдеры; для иллюстрации ниже упрощённый UPDATE с явным приведением (int) для первичного ключа.
$apiKey = getenv('GOOGLE_MAPS_SERVER_KEY');
if ($apiKey === false || $apiKey === '') {
throw new RuntimeException('Missing GOOGLE_MAPS_SERVER_KEY');
}
$addresses = []; // здесь загрузите SELECT из своей таблицы stores
foreach ($addresses as $row) {
$id = (int) $row['id'];
$line = trim((string) $row['address']);
if ($line === '') {
continue;
}
try {
$coords = resolve_address_geocode($line, $apiKey);
} catch (Throwable $e) {
error_log('[geocode] stop: ' . $e->getMessage());
break;
}
if ($coords === null) {
continue;
}
// Пример только для понятности; на бою лучше prepare/execute
printf("UPDATE shops_geo SET lat = %f, lng = %f, is_loc_checked = 1 WHERE id = %d;\n",
$coords['lat'],
$coords['lng'],
$id
);
}Связь с типовым кодом Bitrix
Такие скрипты обычно крутят из cron с однократным подключением пролога ядра, если нужен контекст сайта или COption для секрета. Для высокочастотного импорта разумнее отложить геокодирование из фонового агента с паузой между запросами, чтобы не упереться в лимиты поставщика и не блокировать интернет‑магазин.
Кратко
- Координаты по адресу — через официальный Geocoding API поверх HTTPS и с ограниченным ключом.
- Флаг
is_loc_checkedэкономит повторные вызовы и помогает отделить «ещё не пробовали» от «пробовали и не нашли». - Широта и долгота — тип float/decimal и параметризованный запрос, не строки с экранированием.
- Превышение квоты обрабатывайте явно: лог, отложенный повтор, алерт.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии