json_encode renvoie NULL?

119

Pour une raison quelconque, l'élément «description» revient NULLavec le code suivant:

<?php
include('db.php');

$result = mysql_query('SELECT * FROM `staff` ORDER BY `id` DESC LIMIT 2') or die(mysql_error());
$rows = array();
while($row = mysql_fetch_assoc($result)){
    $rows[] = $row;
}

echo json_encode($rows);
?>

Voici le schéma de ma base de données:

CREATE TABLE `staff` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` longtext COLLATE utf8_unicode_ci,
  `description` longtext COLLATE utf8_unicode_ci,
  `icon` longtext COLLATE utf8_unicode_ci,
  `date` longtext COLLATE utf8_unicode_ci,
  `company` longtext COLLATE utf8_unicode_ci,
  `companyurl` longtext COLLATE utf8_unicode_ci,
  `appurl` longtext COLLATE utf8_unicode_ci,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Voici ce qui est repris sur la page:

[{"id":"4","name":"Noter 2","description":null,"icon":"http:\/\/images.apple.com\/webapps\/productivity\/images\/noter2_20091223182720-thumb.jpg","date":"1262032317","company":"dBelement, LLC","companyurl":"http:\/\/dbelement.com\/","appurl":"http:\/\/noter2.dbelement.com"},{"id":"3","name":"Noter 2","description":null,"icon":"http:\/\/images.apple.com\/webapps\/productivity\/images\/noter2_20091223182720-thumb.jpg","date":"1262032317","company":"dBelement, LLC","companyurl":"http:\/\/dbelement.com\/","appurl":"http:\/\/noter2.dbelement.com"}]

Des idées?

Tarnfeld
la source
Mettons d'abord les clés du tableau entre guillemets.
Joost
Pourriez-vous fournir des informations sur le schéma de votre table "staff". Y a-t-il une colonne appelée description?
mopoke
tous ces champs se répercuteront si je fais simplement un écho à l' $r['description']extérieur de l'instruction for ()?
tarnfeld
Ou peut-être qu'un exemple de contenu de $ r ['description'] serait utile. De quel type de données s'agit-il?
mopoke
pouvez-vous faire une capture d'écran du shema de la base de données? ;-)
streetparade

Réponses:

256

Je parie que vous récupérez des données dans un encodage non utf8: essayez de mettre mysql_query('SET CHARACTER SET utf8')avant votre SELECTrequête.

ntd
la source
5
salut, cette réponse m'a sauvé la vie, merci. J'avais le même problème ici. J'avais des valeurs avec des caractères non utf8 comme "Validação de Formulários". Je sais que cette question est un peu vieille maintenant, mais c'est la génialité d'Internet !!
fabio
7
mysql_set_charset est meilleur pour des raisons de sécurité depuis PHP 5.2.3. Voir php.net/manual/en/function.mysql-set-charset.php pour les détails.
masakielastic
3
Parce que UTF8 est la lingua franca sur le Web. Au lieu d'encombrer l'API avec des paramètres et des frais généraux supplémentaires, PHP utilise (rigoureusement) l'encodage le plus courant, vous laissant le fardeau de la conversion si vous utilisez un encodage inhabituel (ou presque mort, comme dans votre cas).
ntd
1
La manière recommandée de procéder a maintenant changé. J'ai essayé de modifier cette réponse pour inclure un lien, mais j'ai été rejetée. La bonne manière est dans ma réponse ci-dessous.
bejs
1
@VeeK il ne suffit pas d'avoir vos champs stockés en UTF-8: vous devez configurer votre serveur pour répondre aux clients en UTF-8. AFAIK stock mysql et mariadb utilisent latin1.
ntd
118

Si vous avez au moins PHP 5.5, vous pouvez utiliser json_last_error_msg () , qui retournera une chaîne décrivant le problème.

Si vous n'avez pas 5.5, mais êtes sur / au-dessus de 5.3, vous pouvez utiliser json_last_error () pour voir quel est le problème.

Il renverra un entier, que vous pourrez utiliser pour identifier le problème dans la documentation de la fonction . Actuellement (2012.01.19), les identifiants sont:

0 = JSON_ERROR_NONE
1 = JSON_ERROR_DEPTH
2 = JSON_ERROR_STATE_MISMATCH
3 = JSON_ERROR_CTRL_CHAR
4 = JSON_ERROR_SYNTAX
5 = JSON_ERROR_UTF8

Celles-ci peuvent changer dans les versions futures, il est donc préférable de consulter le manuel.

Si vous êtes en dessous de 5,3, vous n'avez pas de chance, il n'y a aucun moyen de demander quelle était l'erreur.

K. Norbert
la source
18

La réponse de ntd n'a pas résolu mon problème. Pour ceux qui sont dans la même situation, voici comment j'ai finalement géré cette erreur: juste utf8_encode chacun de vos résultats.

while($row = mysql_fetch_assoc($result)){
    $rows[] = array_map('utf8_encode', $row);
}

J'espère que ça aide!

Pablo Abdelhay
la source
J'ai eu des problèmes d'encodage aussi. avec encodage mixte. solution que j'ai trouvée: stackoverflow.com/a/3521396/776345
Paschalis
9

il y a quelques jours, j'ai le MÊME problème avec 1 table.

Essayez d'abord:

echo json_encode($rows);
echo json_last_error();  // returns 5 ?

Si la dernière ligne renvoie 5, le problème vient de vos données . Je sais, vos tableaux sont en UTF-8, mais pas de données saisies . Par exemple, l'entrée était dans un fichier txt, mais créée sur une machine Win avec un codage stupide (dans mon cas Win-1250 = CP1250) et ces données ont été entrées dans le DB.

Solution? Recherchez de nouvelles données (Excel, page Web), modifiez le fichier txt source via PSPad (ou autre chose), changez le codage en UTF-8 , supprimez toutes les lignes et mettez maintenant les données de l'original. Sauver. Entrez dans DB .

Vous pouvez également modifier uniquement le codage en utf-8, puis modifier toutes les lignes manuellement (donner des cols avec des caractères spéciaux - desc, ...). Bon pour les esclaves ...

Ivo Urbanek
la source
ou utilisez l' JSON_PARTIAL_OUTPUT_ON_ERRORoption pour voir le problème (par exemple, le champ avec UTF8 sera nul).
Peter Krauss
6

Vous devez passer la chaîne encodée en utf8 dans json_encode. Vous pouvez utiliser utf8_encodeet array_map()fonctionner comme ci-dessous:

<?php
    $encoded_rows = array_map('utf8_encode', $rows);
    echo json_encode($encoded_rows);
?>
Koder
la source
4

AHHH !!! Cela semble tellement faux que cela me fait mal à la tête. Essayez quelque chose de plus comme ça ...

<?php
include('db.php');

$result = mysql_query('SELECT `id`, `name`, `description`, `icon` FROM `staff` ORDER BY `id` DESC LIMIT 20') or die(mysql_error());
$rows = array();
while($row = mysql_fetch_assoc($result)){
    $rows[] = $row;
}

echo json_encode($rows);
?>
  • Lorsque vous répétez, mysql_num_rowsvous ne devez <pas utiliser <=. Vous devez également mettre en cache cette valeur (l'enregistrer dans une variable) au lieu de la recompter chaque boucle. Qui sait ce qu'il fait sous le capot ... (peut-être efficace, je ne suis pas vraiment sûr)
  • Vous n'avez pas besoin de copier chaque valeur explicitement comme ça ... vous ne faites que rendre cela plus difficile pour vous-même. Si la requête renvoie plus de valeurs que celles que vous avez répertoriées, répertoriez uniquement celles que vous souhaitez dans votre SQL.
  • mysql_fetch_arrayrenvoie les valeurs par keyet par int. Vous n'utilisez pas les index, alors ne les récupérez pas.

Si cela pose vraiment un problème avec json_encode, puis-je suggérer de remplacer le corps de la boucle par quelque chose comme

$rows[] = array_map('htmlentities',$row);

Peut-être qu'il y a des caractères spéciaux là-dedans qui salissent les choses ...

mpen
la source
[{"id": "4", "name": "Noter 2", "description": null, "icon": "http: \ / \ / images.apple.com \ / webapps \ / productivité \ / images \ /noter2_20091223182720-thumb.jpg "," date ":" 1262032317 "," société ":" dBelement, LLC "," companyurl ":" http: \ / \ / dbelement.com \ / "," appurl ":" http: \ / \ / noter2.dbelement.com "}, {" id ":" 3 "," name ":" Noter 2 "," description ": null," icon ":" http: \ / \ / images .apple.com \ / webapps \ / productivité \ / images \ /noter2_20091223182720-thumb.jpg "," date ":" 1262032317 "," société ":" dBelement, LLC "," companyurl ":" http: \ / \ /dbelement.com\/","appurl":"http:\/\/noter2.dbelement.com "
tarnfeld
@tarnfield: Eh bien, c'est ce que vous voulez ou pas? Oh ... vous avez des informations supplémentaires là-dedans ... ici ... laissez-moi régler cela pour vous.
mpen
ouais "description" revientnull
tarnfeld
Si la description revient nullalors il probablement est null . Essayez echo $row['description'].'<br/>';dans cette boucle et voyez ce qu'elle dit.
mpen
1
salut, cette réponse m'a sauvé la vie, merci. J'avais le même problème ici. J'avais des valeurs avec des caractères non utf8 comme "Validação de Formulários". Je sais que cette question est un peu vieille maintenant, mais c'est la génialité d'Internet !!
fabio
3

Pour toute personne utilisant PDO, la solution est similaire à la réponse de ntd .

Depuis la page PHP PDO :: __ construct , en tant que commentaire de l'utilisateur Kiipa sur live dot com :

Pour obtenir le jeu de caractères UTF-8, vous pouvez le spécifier dans le DSN.

$ link = new PDO ("mysql: host = localhost; dbname = DB; charset = UTF8 ");

MichaelS
la source
0

Pour moi, un problème où json_encode retournait un encodage nul d'une entité était dû au fait que mon implémentation jsonSerialize récupérait des objets entiers pour les entités associées; J'ai résolu le problème en m'assurant que j'ai récupéré l'ID de l'entité associée / associée et appelé -> toArray () lorsqu'il y avait plus d'une entité associée à l'objet à sérialiser json. Remarque, je parle de cas où un implements JsonSerializablesur les entités.

Victor S
la source
-4

J'ai eu le même problème et la solution était d'utiliser ma propre fonction au lieu de json_encode()

echo '["' . implode('","', $row) . '"]';
Laci
la source