Проблемы с кодировкой в ответе геокодера

73
22 сентября 2021, 21:20

Пытаюсь получить координаты по названию объекта в формате JSON, но в ответе геокодера вместо названия объекта набор символов. Раньше код работал, но недавно в Яндексе изменились требования и начались проблемы. техподдержка Яндекс говорит что теперь геокодер принимает только UTF-8 кодировку. Ок, настроил сервер, и внутреннюю кодировку на UTF-8. Для запроса координат, например, Санкт-Петербурга в ответ прилетает это СанкÑ-ÐеÑеÑбÑÑг. В таком формате:

array(1) { ["response"]=> array(1) { ["GeoObjectCollection"]=> array(2) { ["metaDataProperty"]=> array(1) { ["GeocoderResponseMetaData"]=> array(3) { ["request"]=> string(57) "СанкÑ-ÐеÑеÑбÑÑг" ["results"]=> string(2) "10" ["found"]=> string(1) "0" } } ["featureMember"]=> array(0) { } } } }

Тестовый код:

header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding('UTF-8');
mb_http_output ('UTF-8');
mb_http_input ('UTF-8');
error_reporting(E_ALL);
$user_2 = "Санкт-Петербург";
$url = 'https://geocode-maps.yandex.ru/1.x/?format=json&apikey=c910121a-bfc1-479e-a7d1-xxx&geocode='.$user_2;
$ar = json_decode(file_get_contents($url),true);
$coords = $ar['response']['GeoObjectCollection']['featureMember']['GeoObject']['Point']['pos'];
list($lon,$lat) = explode(' ',$coords);
$lon = +$lon;
$lat = +$lat;
echo "</br></br>";
print_r("Кодировка переменной 'user_2': ");
echo mb_detect_encoding($user_2);
echo "</br></br>";
print_r("Содержимое переменной 'user_2': ");
print_r ($user_2);
echo "</br></br>";
print_r("Кодировка сформированного запроса для геокодера: ");
echo mb_detect_encoding($url);
echo "</br></br>";
print_r("Вид запроса для геокодера: ");
print_r ($url);
echo "</br></br>";
print_r("Кодировка данных, полученных от геокодера: ");
echo mb_detect_encoding($ar['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['request']);
echo "</br></br>";
print_r("Содержимое массива: ");
var_dump ($ar);

Результат выполнения кода:

Notice: Undefined index: GeoObject in C:\xampp\htdocs\test\testData.php on line 11
Notice: Undefined offset: 1 in C:\xampp\htdocs\test\testData.php on line 12
Warning: A non-numeric value encountered in C:\xampp\htdocs\test\testData.php on line 13

Кодировка переменной 'user_2': UTF-8
Содержимое переменной 'user_2': Санкт-Петербург
Кодировка сформированного запроса для геокодера: UTF-8
Вид запроса для геокодера: https://geocode-maps.yandex.ru/1.x/?format=json&apikey=c910121a-bfc1-479e-a7d1-xxx&geocode=Санкт-Петербург
Кодировка данных, полученных от геокодера: UTF-8
Содержимое массива: array(1) { ["response"]=> array(1) { ["GeoObjectCollection"]=> array(2) { ["metaDataProperty"]=> array(1) { ["GeocoderResponseMetaData"]=> array(3) { ["request"]=> string(57) "СанкÑ-ÐеÑеÑбÑÑг" ["results"]=> string(2) "10" ["found"]=> string(1) "0" } } ["featureMember"]=> array(0) { } } } }

Кто подскажет как правильно кодировать запрос для геокодера? Видно что запрос сформирован в UTF-8, ответ тоже получен в UTF-8 но при этом в виде кракозябр. Сторонние кодировщики говорят что значение в массиве в кодировке ISO-8859-1, но я как понимаю ISO-8859-1 полностью совместима с UTF-8.

Answer 1

В результате выполнения, видно что проблема в строке 11, в массиве нет ключа GeoObject

попробуйте так:

header('Content-Type: text/html; charset=utf-8');
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
mb_http_input('UTF-8');
error_reporting(E_ALL);
$user_2 = "Санкт-Петербург";
$url = 'https://geocode-maps.yandex.ru/1.x/?format=json&apikey=c910121a-bfc1-479e-a7d1-xxx&geocode=' . $user_2;
$ar = json_decode(file_get_contents($url), true);
$coords = getRawCoords($ar);
if (empty($coords)) {
    var_dump($ar);
}
list($lon, $lat) = explode(' ', $coords);
$lon = +$lon;
$lat = +$lat;
echo "</br></br>";
print_r("Кодировка переменной 'user_2': ");
echo mb_detect_encoding($user_2);
echo "</br></br>";
print_r("Содержимое переменной 'user_2': ");
print_r($user_2);
echo "</br></br>";
print_r("Кодировка сформированного запроса для геокодера: ");
echo mb_detect_encoding($url);
echo "</br></br>";
print_r("Вид запроса для геокодера: ");
print_r($url);
echo "</br></br>";
print_r("Кодировка данных, полученных от геокодера: ");
echo mb_detect_encoding($ar['response']['GeoObjectCollection']['metaDataProperty']['GeocoderResponseMetaData']['request']);
echo "</br></br>";
print_r("Содержимое массива: ");
var_dump($ar);
function getRawCoords(array $response)
{
    switch (true) {
        case !isset($response['response']):
        case !isset($response['response']['GeoObjectCollection']):
        case !isset($response['response']['GeoObjectCollection']['featureMember']):
        case !isset($response['response']['GeoObjectCollection']['featureMember']['GeoObject']):
        case !isset($response['response']['GeoObjectCollection']['featureMember']['GeoObject']['Point']):
        case !isset($response['response']['GeoObjectCollection']['featureMember']['GeoObject']['Point']['pos']):
            return null;
        default:
            return $response['response']['GeoObjectCollection']['featureMember']['GeoObject']['Point']['pos'];
    }
}

Таким образом, вы поймете, что за ошибка возвращается вам

Answer 2

Столкнулась с такой же проблемой, сервер на Tomcat. Изменение кодировки в Tomcate решило проблему:

set "CATALINA_OPTS=%CATALINA_OPTS% -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"
Answer 3

Нужно экранировать текст запроса функцией urlencode(). В Вашем конкретном случае нужно экранировать переменную $user_2.

READ ALSO
Калькулятор html + php

Калькулятор html + php

Изучая php, решил написать простой калькулятор на phpИмеются два input для двух значений, select для выбора математической операции и submit

174
Как реализовать формулу для расчета даты?

Как реализовать формулу для расчета даты?

Подскажите, пожалуйста, как реализовать следующее

175
Перебор масивов через регулярку

Перебор масивов через регулярку

Как перебрать многомерный массив ? Массив

75