Por que a função json_encode do PHP converte cadeias UTF-8 em entidades hexadecimais?

148

Eu tenho um script PHP que lida com uma grande variedade de idiomas. Infelizmente, sempre que tento usar json_encode, qualquer saída Unicode é convertida em entidades hexadecimais. Este é o comportamento esperado? Existe alguma maneira de converter a saída em caracteres UTF-8?

Aqui está um exemplo do que estou vendo:

ENTRADA

echo $text;

RESULTADO

База данни грешка.

ENTRADA

json_encode($text);

RESULTADO

"\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u0438 \u0433\u0440\u0435\u0448\u043a\u0430."
David Jones
fonte

Respostas:

355

Desde o PHP / 5.4.0, existe uma opção chamada "JSON_UNESCAPED_UNICODE". Confira:

http://se2.php.net/json_encode

Portanto, você deve tentar:

json_encode( $text, JSON_UNESCAPED_UNICODE );
John Severinson
fonte
3
Aha. Obrigado! Eu deveria ter lido a documentação com mais cuidado. Obrigado.
David Jones
3
JSON_UNESCAPED_UNICODE foi introduzido no PHP 5.4.0 e não está disponível nas versões anteriores. Ao usá-lo nas versões anteriores, você receberá este erro: "Aviso: json_encode () espera que o parâmetro 2 seja longo, string fornecida em ...". Veja a resposta da CertaiN abaixo para a solução 5.3.
Octavian Naicu
Isso também funciona com as letras dinamarquesas Æ, æ, Ø, ø, Å, å Obrigado!
precisa saber é o seguinte
Fantástico, esta foi a resposta que eu estava procurando!
Random #
2
Você acabou de salvar minha vida. OBRIGADO.
Jon Zangitu
57

JSON_UNESCAPED_UNICODE está disponível no PHP Versão 5.4 ou posterior.
O código a seguir é para a versão 5.3.

ATUALIZADA

  • html_entity_decodeé um pouco mais eficiente que pack+ mb_convert_encoding.
  • (*SKIP)(*FAIL)pula barras invertidas e caracteres especificados por JSON_HEX_*sinalizadores.

 

function raw_json_encode($input, $flags = 0) {
    $fails = implode('|', array_filter(array(
        '\\\\',
        $flags & JSON_HEX_TAG ? 'u003[CE]' : '',
        $flags & JSON_HEX_AMP ? 'u0026' : '',
        $flags & JSON_HEX_APOS ? 'u0027' : '',
        $flags & JSON_HEX_QUOT ? 'u0022' : '',
    )));
    $pattern = "/\\\\(?:(?:$fails)(*SKIP)(*FAIL)|u([0-9a-fA-F]{4}))/";
    $callback = function ($m) {
        return html_entity_decode("&#x$m[1];", ENT_QUOTES, 'UTF-8');
    };
    return preg_replace_callback($pattern, $callback, json_encode($input, $flags));
}
mpyw
fonte
1
Não deveria ser \ U, ou seja, maiúscula?
malhal
4
Boa solução para PHP <5.4;)
qdev
Eu estava procurando por três dias para encontrar esta solução para a versão 5.3, pois meu host não foi atualizado para a versão 5.4. Para mim, você é um salva-vidas e, por ser tão completo, prefiro marcar isso como resposta aceita!
Laci
Corrigido o erro quando a string continha \\ . A versão mais recente agarra \\ prioridade mais alta que \u.
mpyw
Isso deve ser adicionado na biblioteca php. Bom trabalho.
Beraki
7

Você deseja definir charset e unicode sem escape

 header('Content-Type: application/json;charset=utf-8');  
 json_encode($data,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
Adrian Romero
fonte
4

Uma solução é primeiro codificar os dados e depois decodificá-los no mesmo arquivo:

$string =json_encode($input, JSON_UNESCAPED_UNICODE) ; 
echo $decoded = html_entity_decode( $string );
Steffo Dimfelt
fonte
1

Aqui está minha solução combinada para várias versões do PHP.

Na minha empresa, estamos trabalhando com diferentes servidores com várias versões do PHP, então tive que encontrar uma solução que funcionasse para todos.

$phpVersion = substr(phpversion(), 0, 3)*1;

if($phpVersion >= 5.4) {
  $encodedValue = json_encode($value, JSON_UNESCAPED_UNICODE);
} else {
  $encodedValue = preg_replace('/\\\\u([a-f0-9]{4})/e', "iconv('UCS-4LE','UTF-8',pack('V', hexdec('U$1')))", json_encode($value));
}

Os créditos devem ir para Marco Gasi e Abu . A solução para PHP> = 5.4 é fornecida nos documentos json_encode.

gaba
fonte
0

A função raw_json_encode () acima não me resolveu o problema (por algum motivo, a função de retorno de chamada gerou um erro no meu servidor PHP 5.2.5).

Mas essa outra solução realmente funcionou.

https://www.experts-exchange.com/questions/28628085/json-encode-fails-with-special-characters.html

Os créditos devem ir para Marco Gasi . Eu apenas chamo sua função em vez de chamar json_encode ():

function jsonRemoveUnicodeSequences( $json_struct )
{ 
    return preg_replace( "/\\\\u([a-f0-9]{4})/e", "iconv('UCS-4LE','UTF-8',pack('V', hexdec('U$1')))", json_encode( $json_struct ) );
}
abu
fonte
0
json_encode($text, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
Hoàng Vũ Tgtt
fonte
-2

Desde que você perguntou:

Existe alguma maneira de converter a saída em caracteres UTF-8?

Outra solução é usar utf8_encode .

Isso codificará sua string para UTF-8.

por exemplo

foreach ($rows as $key => $row) {
  $rows[$key]["keyword"] = utf8_encode($row["keyword"]);
}

echo json_encode($rows);
Robin Carlo Catacutan
fonte
2
Não use isso. Conforme declarado na página de documento PHP, utf8_encode só é apropriado se a sua string original for codificada em ISO-8859-1 (Latin1). Essa não é uma função "certifique-se de que essa string seja codificada em utf-8".
Telomere