Номера кодирования PHP json_encode в виде строк


145

У меня одна проблема с функцией PHP json_encode. Он кодирует числа как строки, например

array('id' => 3)

становится

"{ ["id": "3", ...)

Когда js встречает эти значения, он интерпретирует их как строки, и числовые операции с ними не выполняются. Кто-нибудь знает, как предотвратить json_encodeкодирование чисел в виде строк? Спасибо!


Оказывается, это проблема конкретной версии. Иногда при извлечении из базы данных MySql поддерживаются правильные типы. В более старых версиях он может возвращать все в виде строки. Я писал об этом сегодня утром. shakyshane.com/blog/output-json-from-php.html
шейн

1
У меня была такая же проблема, и я смог решить ее, используя мутаторы Laravel в модели. Это позволяет вам изменять значения в модели. laravel.com/docs/eloquent#accessors-and-mutators Сначала я не совсем понял , но этот вопрос помог: stackoverflow.com/questions/16985656/…
Jazzy

Ответы:


29

Я сделал очень быстрый тест:

$a = array(
    'id' => 152,
    'another' => 'test',
    'ananother' => 456,
);
$json = json_encode($a);
echo $json;

Кажется, это похоже на то, что вы описываете, если я не ошибаюсь?

И я получаю как результат:

{"id":152,"another":"test","ananother":456}

Итак, в этом случае целые числа не были преобразованы в строку.


Тем не менее, это может зависеть от версии PHP, которую мы используем: было исправлено несколько ошибок, связанных с json_encode, в зависимости от версии PHP ...

Этот тест был проведен с PHP 5.2.6; Я получаю то же самое с PHP 5.2.9 и 5.3.0; Но у меня нет другой версии 5.2.x для тестирования :-(

Какую версию PHP вы используете? Или ваш тестовый пример сложнее, чем опубликованный вами пример?

Может быть, может быть связан один отчет об ошибке на http://bugs.php.net/ ? Например, ошибка №40503: целочисленное преобразование json_encode несовместимо с PHP ?


Может быть, ошибка №38680 вас тоже заинтересует?


Спасибо, Мартин. Пользуюсь 5.2.9. Интересно, читаются ли числовые данные из БД как строка? Я уверен, что это типы полей int, но я не могу придумать другого объяснения. Я попробую ваш быстрый тест на своей системе и посмотрю, получу ли я такой же результат.
Крис Барнхилл,

13
ОК около 5.2.9; если ваши данные поступают из базы данных, проблема может быть там: я часто видел, что данные поступают из базы данных со всем приведенным в строку (я видел это с PDO и mssql; но, если я правильно помню, это тоже происходит для MySQL в PHP <5.3, когда новый драйвер mysqlnd еще не существовал) ;; чтобы проверить, как выглядят ваши данные, вы можете использовать var_dump, который выводит типы каждой части данных.
Паскаль МАРТИН,

(продолжение) считает, что тип данных для числовых значений - строка? Любые идеи?
Крис Барнхилл,

1
Я точно не знаю техническую причину того, «почему данные возвращаются из MySQL в виде строки» ;; возможно, что-то, что связано с драйвером между PHP и MySQL ;; это то, что (по крайней мере, в некоторых случаях) исправляется новым драйвером mysqlnd, который поставляется с PHP 5.3 (см. blog.ulf-wendel.de/?p=184 ; ищите "целое число" на странице, чтобы найти интересное предложение) ;; но я согласен, что это нехорошо ^^
Паскаль МАРТИН

Не имеет значения, что числовые данные, возвращаемые json_encode (), не заключены в кавычки, это все равно строка. Возвращаемое значение функции json_encode () - строка. Что касается MySQL, возвращающего все поля в виде строк, да, я также столкнулся с этим специально с PDO. На мой взгляд, вы всегда должны приводить значения, которые, как вы ожидаете, должны быть числовыми, к целым (или с плавающей запятой) в PHP, чтобы убедиться, что MySQL или любая другая база данных не вернет значения правильного типа.
Ричард Кноп,

360

Обратите внимание, что, начиная с PHP 5.3.3, есть флаг для автоматического преобразования чисел (параметр options был добавлен в PHP 5.3.0):

$arr = array( 'row_id' => '1', 'name' => 'George' );
echo json_encode( $arr, JSON_NUMERIC_CHECK ); // {"row_id":1,"name":"George"}

5
Обратите внимание, что JSON_NUMERIC_CHECK требует PHP 5.3.3.
Роберт

10
Работал отлично, пока не преобразовал числовую метку в целое число, взорвав .toLowerCase () в IE. Будьте осторожны, это простое решение, но слишком усердное.
Брэд Кох

5
Это имеет некоторый побочный эффект, если ваша строка не число, а такое содержимое: 5252788e16597. ссылка: bugs.php.net/bug.php?id=64695
TonyQ

20
JSON_NUMERIC_CHECKпытается автоматически угадать, является ли строка числом или нет, пытаясь разобрать ее. Если задуматься, это довольно ненадежно. Он преобразует все числовые свойства в числа (а не только те, которые вам нужны), и будет делать это, только если они выглядят как числа. Это, по крайней мере, ненадежно, если не небезопасно. Код, который использует созданный JSON, может полагаться на тот или иной тип. Если эти ожидания не оправдаются, могут случиться странные вещи. Если вы заботитесь о передовых методах работы и безопасности, вам следует выборочно преобразовывать нужные вам значения.
wadim

3
Как упоминалось Брэдом и Вадимом, JSON_NUMERIC_CHECK имеет побочный эффект, который преобразует допустимые строки в числовые значения. Чтобы преодолеть это, если вы знаете тип каждого поля, вы можете использовать следующий обходной путь: объединить со значением любого строкового поля «маркер» (например, «this_is_a_string»), затем выполнить json_encode с параметром JSON_NUMERIC_CHECK и, наконец, удалил маркер из json-строки: $ cleaned_json = str_replace ('this_is_a_string', '', $ Marked_json). Не изящно, но у меня сработало.
Doigen 05

35

Я тоже читал из БД (PostgreSQL), и все было строкой. Мы перебираем каждую строку и делаем с ней что-то, чтобы создать наш окончательный массив результатов, поэтому я использовал

$result_arr[] = array($db_row['name'], (int)$db_row['count']);

внутри цикла, чтобы оно было целочисленным значением. Когда я это делаю json_encode($result_arr)сейчас, он правильно форматирует его как число. Это позволяет вам контролировать, какие числа поступают из вашей базы данных, а какие нет.

РЕДАКТИРОВАТЬ:

json_encode()Функция также имеет возможность сделать это на лету , используя JSON_NUMERIC_CHECKфлаг в качестве второго аргумента к нему. Вы должны быть осторожны, используя его, хотя, как показано в этом примере пользователей в документации (скопировано ниже): http://uk3.php.net/manual/en/function.json-encode.php#106641

<?php
// International phone number
json_encode(array('phone_number' => '+33123456789'), JSON_NUMERIC_CHECK);
?>

И тогда вы получите этот JSON:

{"phone_number":33123456789}

да, похоже, проблема в адаптере БД, который не интерпретирует типы данных, а НЕ json_encodeфункции. это наиболее правильный ответ, но будьте осторожны, поскольку JSON_NUMERIC_CHECKконвертирует также номера телефонов и другие числовые строковые значения, и это может вызвать проблемы с начальными нулями или «+» ... Я предлагаю исправить эту проблему в функции чтения БД.
caesarsol

9

пытаться $arr = array('var1' => 100, 'var2' => 200);
$json = json_encode( $arr, JSON_NUMERIC_CHECK);

Но он просто работает на PHP 5.3.3. Посмотрите на этот журнал изменений PHP json_encode http://php.net/manual/en/function.json-encode.php#refsect1-function.json-encode-changelog


Это сработало для меня. Установка PHP + apache по умолчанию на debian squeeze 6.0.5 с данными, поступающими из postgre db
Николай Спасов

7

У меня такая же проблема (PHP-5.2.11 / Windows). Я использую этот обходной путь

$json = preg_replace( "/\"(\d+)\"/", '$1', $json );

который заменяет все (неотрицательные, целые) числа, заключенные в кавычки, самим числом («42» становится «42»).

См. Также этот комментарий в руководстве по PHP .


Спасибо за код, но, к сожалению, он не сработал на моем json, потому что у меня есть число в качестве имени объекта, и похоже, что json недействителен :(
SSH This

@SSHThis, возможно, вам следует использовать этот синтаксис для преобразования массива в массив в кодировке JSON, а не в объект. $json_array = json_encode($some_array, false);Таким образом, аргумент false указывает PHP не выполнять преобразование объекта.
hyde

Использовать этот обходной путь совсем небезопасно. Вы получите недействительный json с такими структурами:json_encode(array(-1=>'que', '0'=>'-1'))
Алекс Ярошевич

У меня была проблема наоборот, мне нужны были мои целые числа, закодированные в виде строк в PHP 7.0, и я использовал это$this->data = preg_replace("/\" *?: *?(\d+)/", '":"$1"', $this->data);
Maciej Swic

Я изменю исходное регулярное выражение на "/\"(\d+\.?\d*)\"/" `, чтобы включить десятичные дроби, еще одно примечание: ребята, которые используют JSON_NUMERIC_CHECK, столкнутся с проблемой, когда строка также является правильной число в экспоненциальной записи. например, 19E008. JSON_NUMERIC_CHECK преобразует его в 190000 ...
Сахиб Хан

3

Следующий тест подтверждает, что изменение типа на строку приводит к тому, что json_encode () возвращает число в виде строки JSON (т. Е. В двойных кавычках). Используйте settype (arr ["var"], "integer") или settype ($ arr ["var"], "float"), чтобы исправить это.

<?php

class testclass {
    public $foo = 1;
    public $bar = 2;
    public $baz = "Hello, world";
}

$testarr = array( 'foo' => 1, 'bar' => 2, 'baz' => 'Hello, world');

$json_obj_txt = json_encode(new testclass());
$json_arr_txt = json_encode($testarr);

echo "<p>Object encoding:</p><pre>" . $json_obj_txt . "</pre>";
echo "<p>Array encoding:</p><pre>" . $json_arr_txt . "</pre>";

// Both above return ints as ints. Type the int to a string, though, and...
settype($testarr["foo"], "string");
$json_arr_cast_txt = json_encode($testarr);
echo "<p>Array encoding w/ cast:</p><pre>" . $json_arr_cast_txt . "</pre>";

?>

3

Итак, Паскаль МАРТИН не получает здесь достаточного признания. Проверка числовых значений при каждом возврате JSON невозможна для существующего проекта с сотнями функций на стороне сервера.

Я заменил php-mysql на php-mysqlnd, и проблема исчезла. Числа - это числа, строки - это строки, логические значения - это логические.


2

Для полноты (поскольку я пока не могу добавлять комментарии) позвольте мне также добавить эту деталь в качестве еще одного ответа:

(Изменить: для чтения после осознания того, что исходные данные (т.е. в случае OP, набор результатов базы данных) могут быть проблемой (путем возврата числовых столбцов в виде строк), а json_encode () на самом деле не был источником проблемы)

Страницы руководства для " mysql_fetch_array ":

Возвращает массив строк , соответствующий выбранной строке,

... и " mysql_ fetch_ row ":

Возвращает числовой массив строк , соответствующий выбранной строке.

четко заявляет, что; записи в возвращаемом массиве будут строками.

(Я использовал класс DB в phpBB2 (да, я знаю, он устарел!), А метод sql_fetchrow () этого класса использует mysql_fetch_array ())

Не осознавая этого, я тоже нашел этот вопрос и понял проблему! :)

Как Паскаль Мартин заявил выше в своих последующих комментариях, я считаю, что решение, которое решает проблему «неправильного типа» в источнике (то есть, используя функцию « mysql_field_type () » и выполняя приведение сразу после выборки, (или другие методы выборки, такие как "объект"?)) в целом были бы лучше.


0

У меня тоже была такая же проблема с обработкой данных из базы данных. В основном проблема в том, что тип массива, который нужно преобразовать в json, распознается PHP как строка, а не как целое число. В моем случае я сделал запрос, который возвращает данные из строки подсчета столбцов БД. Драйвер PDO распознает столбец не как int, а как строки. Я решил, выполнив приведение к типу int в затронутом столбце.


0
$rows = array();
while($r = mysql_fetch_assoc($result)) {
    $r["id"] = intval($r["id"]); 
    $rows[] = $r;
}
print json_encode($rows);  

0

это проблема с версией php, если та же проблема обновила мою версию php до 5.6, проблема была решена


0

Приведение значений к int или float, кажется, исправляет это. Например:

$coordinates => array( 
    (float) $ap->latitude,
    (float) $ap->longitude 
);

0

Вы можете использовать (int), если возникнут какие-либо проблемы !! Будет работать нормально.


-1

Просто столкнитесь с той же проблемой, и база данных возвращает значения в виде строк.

Я использую это как обходной путь:

$a = array(
    'id' => $row['id'] * 1,
    'another' => ...,
    'ananother' => ...,
);
$json = json_encode($a);

Это умножение значения на 1, чтобы преобразовать его в число

Надеюсь, это кому-то поможет


использование множителя - не самое эффективное решение. рассмотрите возможность использования JSON_NUMERIC_CHECK в json_encode, поскольку он автоматически исправит это
Эрик

-2

json_encode сериализует некоторые структуры данных в формате JSON для отправки по сети. Следовательно, все содержимое будет иметь строковый тип. Так же, как когда вы получаете какой-то параметр от $ _POST или $ _GET.

Если вам нужно выполнить числовые операции с отправленными значениями, просто сначала преобразуйте их в int (с помощью функции intval () в PHP или parseInt () в Javascript), а затем выполните операции.


он не об этом говорит. он говорит о том, что в json числа заключены в двойные кавычки.
JasonWoof

В случае JSON он сохраняет типы. Представьте, что вы записываете буквальный объект JavaScript, любые значения в кавычках становятся строками, а числа, не заключенные в кавычки, становятся целыми, 0x [0-9a-z] становится шестнадцатеричным и т. Д. Существуют различия типов с PHP, например, не существует такой вещи, как ассоциативный массив, просто объекты или индексированные массивы и т. д.
bucabay

верно. Проблема, с которой он столкнулся, заключалась в том, что у него была переменная php, которая, по его мнению, имела тип int, потому что она пришла из столбца БД типа int. Но на самом деле переменная PHP имеет строку типа, следовательно, кавычки в JSON.
JasonWoof

-2

Ну, PHP json_encode () возвращает строку.

Вы можете использовать parseFloat () или parseInt () в js-коде:

parseFloat('122.5'); // returns 122.5
parseInt('22'); // returns 22
parseInt('22.5'); // returns 22

Спасибо. Я надеялся, что есть более элегантный метод.
Крис Барнхилл,

1
да, самый безопасный способ - проанализировать их. но опять же, не является ли Javascript слабо типизированным?
mauris 08

Просто комментарий: он нечетко набран, но результат «1» +1 будет ... 11 - поэтому, используя JS, вы должны быть более внимательными, чем в языках строгого типа, потому что они будут предупреждать вас, JS просто делает то, что думаю, лучше всего будет
работать с числами-строками

Да, но дело не в этом, json_encode не должен добавлять кавычки в числовые поля.
andreszs 09

-3

Как сказал oli_arborum, я думаю, вы можете использовать preg_replaceдля выполнения этой работы. Просто измените команду так:

$json = preg_replace('#:"(\d+)"#', ':$1', $json);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.