UTF-8 для Яндекс.Директ API

Слава Шевцов
На сайте с 23.07.2005
Offline
370
4941

Пример из http://api.yandex.ru/direct/doc/examples/php-sample-json.xml#campaign работает, но кампания в Директе создаётся со строками из квадратиков вместо русских букв. Браузер показывает, что в исходящем запросе на самом деле квадратики вместо русских букв.

Замена utf8_encode($value) на iconv('windows-1251', 'UTF-8', $value) в

# перекодировка строковых данных в UTF-8

function utf8($struct) {
foreach ($struct as $key => $value) {
if (is_array($value)) {
$struct[$key] = utf8($value);
}
elseif (is_string($value)) {
$struct[$key] = utf8_encode($value);
}
}
return $struct;
}

приводит к коректному отображению в браузере строк запроса, но к ошибке от Яндекса "Request encoding is not UTF8".

Что может быть не так?

P.S.:

- Windows XP

- Denver

Неизменность точки зрения неизменно порождает иллюзию понимания.
skAmZ
На сайте с 04.09.2009
Offline
122
#1
Слава Шевцов:
приводит к коректному отображению в браузере строк запроса

C явно указаной кодировкой в браузере?

Пробовал вообще не использовать функцию utf8?

Исходные данные точно в windows-1251 поступают?

Определить utf8 или windows-1251 можно так:

function detectUTF8($string){

return preg_match('%(?:[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+%xs', $string);
}

Или альтернатива:

function detect_encoding($string) {  

static $list = array('utf-8', 'windows-1251');

foreach ($list as $item) {
$sample = iconv($item, $item, $string);
if (md5($sample) == md5($string))
return $item;
}
return null;
}

skAmZ добавил 16.09.2011 в 18:04

форум из функции detectUTF8 хрень сделал... "***91;" - меняем на "[" и "***93;" на "]"

Слава Шевцов
На сайте с 23.07.2005
Offline
370
#2
skAmZ:
C явно указаной кодировкой в браузере?

Именно - с явным указанием utf-8 (выбор в меню).

skAmZ:
Пробовал вообще не использовать функцию utf8?

Пробовал. После засовывания в json_encode, вместо строк с русскими буквами на выходе оказываются null. То есть при преобразовании целиком теряются русские. Яндекс успешно на это ругается.

skAmZ:
Исходные данные точно в windows-1251 поступают?

Да. Беру код из примера Яндекса, сохраняю через FAR в кодировке Win (до сих пор это всегда был windows-1251). Данные находятся прямо в коде-примере, поэтому они точно в windows-1251. На всякий случай делал преобразование windows-1251 - utf-8 - windows-1251 - получал в браузере корректную windows-1251.

skAmZ:
Определить utf8 или windows-1251 можно так:
function detectUTF8($string){

return preg_match('%(?:[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+%xs', $string);
}

Возвращает 0 там, где цифры или английские строки, и 1, где строки русскоязычные:

login int(0)
0 int(0)
No int(0)
Новая кампания int(1)
Иванов Иван Иванович int(1)
login@yandex.ru int(0)
Yes int(0)
1 int(0)
15 int(0)
No int(0)
скачать int(1)
mp3 int(0)
песня int(1)
Yes int(0)
50 int(0)
HighestPosition int(0)
skAmZ:
Или альтернатива:
function detect_encoding($string) {  

static $list = array('utf-8', 'windows-1251');

foreach ($list as $item) {
$sample = iconv($item, $item, $string);
if (md5($sample) == md5($string))
return $item;
}
return null;
}

Везде возвращает не null.

Слава Шевцов добавил 16.09.2011 в 18:25

skAmZ:
форум из функции detectUTF8 хрень сделал... "***91;" - меняем на "[" и "***93;" на "]"

Да. Функция видна корректно в окне цитирования.

skAmZ
На сайте с 04.09.2009
Offline
122
#3
Слава Шевцов:
Возвращает 0 там, где цифры или английские строки, и 1, где строки русскоязычные:

Значит данные уже в utf8.

Но тогда

Слава Шевцов:
Пробовал. После засовывания в json_encode, вместо строк с русскими буквами на выходе оказываются null. То есть при преобразовании целиком теряются русские. Яндекс успешно на это ругается.

Этого не может быть, json_encode так поступает только с русскими символами в кодировке windows-1251. utf8 нормально должен обрабатывать.

Слава Шевцов:
Везде возвращает не null.

Если не null то что?) utf8 или windows-1251?

skAmZ добавил 16.09.2011 в 19:06

А после json_encode русские символы так и остаются русскими или вылдядят примерно так: "\u043b\u043e\u0440\u043b\u043e\u0440"?

skAmZ добавил 16.09.2011 в 19:08

Слава Шевцов:
приводит к коректному отображению в браузере строк запроса

Кстати говоря, у меня русские символы становлятся такими "\u0441\u043a\u0430\u0447\u0430\u0442\u044c" (это слово "песня").

Слава Шевцов
На сайте с 23.07.2005
Offline
370
#4
skAmZ:
Этого не может быть, json_encode так поступает только с русскими символами в кодировке windows-1251. utf8 нормально должен обрабатывать.

Именно это и наблюдается - сую в windows-1251 и получаю null. Сую в utf8 и получаю:

skAmZ:
А после json_encode русские символы так и остаются русскими или вылдядят примерно так: "\u043b\u043e\u0440\u043b\u043e\u0440"?

Точнее вот это:

{"application_id":"xxx19f88151f45c6b21082258d8cxxxx","token":"xxxa32ae774c43dd98e6259b2d1axxxx","login":"login","method":"CreateOrUpdateCampaign","param":{"Login":"login","CampaignID":0,"StatusContextStop":"No","Name":"\u041d\u043e\u0432\u0430\u044f \u043a\u0430\u043c\u043f\u0430\u043d\u0438\u044f","FIO":"\u0418\u0432\u0430\u043d\u043e\u0432 \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432\u0438\u0447","EmailNotification":{"Email":"login@yandex.ru","SendWarn":"Yes","MoneyWarningValue":1,"WarnPlaceInterval":15,"SendAccNews":"No"},"MinusKeywords":["\u0441\u043a\u0430\u0447\u0430\u0442\u044c","mp3","\u043f\u0435\u0441\u043d\u044f"],"AddRelevantPhrases":"Yes","RelevantPhrasesBudgetLimit":50,"Strategy":{"StrategyName":"HighestPosition"}},"locale":"ru"}

В ответ прилетает:

{"error_detail":"Request encoding is not UTF8","error_str":"Invalid request","error_code":501}
skAmZ
На сайте с 04.09.2009
Offline
122
#5

Слава Шевцов, единственное что могу предложить это оставить без изменения фунцию utf8, т.е. не менять utf8_encode. Попробовать так... но почему-то мне кажется что вы уже так пробовали :)

Тогда попробовать сначала данные переконвертировать в ISO-8859-1 и затем пустить их через функцию utf8.

Слава Шевцов
На сайте с 23.07.2005
Offline
370
#6
skAmZ:
Слава Шевцов, единственное что могу предложить это оставить без изменения фунцию utf8, т.е. не менять utf8_encode. Попробовать так... но почему-то мне кажется что вы уже так пробовали

Увы, да. Пробовал. Запрос в Яндекс ушёл успешно, но кампания была создана странно: вместо русских букв - квадратики :(

skAmZ:
Тогда попробовать сначала данные переконвертировать в ISO-8859-1 и затем пустить их через функцию utf8.

Попробовал. Вот что получилось:

{"application_id":"xxx19f88151f45c6b21082258d8c4xxx","token":"xxxa32ae774c43dd98e6259b2d1abxxx","login":"login","method":"CreateOrUpdateCampaign","param":{"Login":"login","CampaignID":0,"StatusContextStop":"No","Name":"","FIO":"","EmailNotification":{"Email":"login@yandex.ru","SendWarn":"Yes","MoneyWarningValue":1,"WarnPlaceInterval":15,"SendAccNews":"No"},"MinusKeywords":["","mp3",""],"AddRelevantPhrases":"Yes","RelevantPhrasesBudgetLimit":50,"Strategy":{"StrategyName":"HighestPosition"}},"locale":"ru"}

То есть вместо русских строк на этот раз подставились пустые строки.

От Яндекса прилетело:

{"error_detail":"Вы должны указать название кампании\nНе заполнено поле ФИО","error_str":"Неверно указаны параметры кампании","error_code":111}
skAmZ
На сайте с 04.09.2009
Offline
122
#7

Слава Шевцов, я тут поковырялся.

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

1. исходную строку имеем в windows-1251.

2. $s=iconv('windows-1251', 'utf-8', $s); // s наша исходная строка

3. $s=iconv('ISO-8859-1', 'utf-8', $s);

И вот полученную строку пускаем через json_encode.

Т.е. вместо исходного "$struct[$key] = utf8_encode($value);". пишем:

$struct[$key] = iconv('ISO-8859-1', 'utf-8', iconv('windows-1251', 'utf-8', $value));

Если и это не поможет то тогда уже только в суппорт)

Слава Шевцов
На сайте с 23.07.2005
Offline
370
#8
skAmZ:
1. исходную строку имеем в windows-1251.
2. $s=iconv('windows-1251', 'utf-8', $s); // s наша исходная строка
3. $s=iconv('ISO-8859-1', 'utf-8', $s);

И вот полученную строку пускаем через json_encode.

Бред какой-то. Но он работает! Спасибо.

skAmZ
На сайте с 04.09.2009
Offline
122
#9

Слава Шевцов, согласен, бред. Но яша декодирует в обратном порядке json_decode -> utf8_decode. От судя и плясали, что нужно передать чтобы после utf8_decode был нормальный русский текст при просмотре в utf8 :)

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий