PHP json_encode, що кодує числа у вигляді рядків


142

У мене є одна проблема з функцією PHP json_encode. Він кодує числа як рядки, наприклад

array('id' => 3)

стає

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

Коли js стикається з цими значеннями, він інтерпретує їх як рядки і числові операції на них не вдається. Хтось знає якийсь спосіб запобігти json_encodeкодування чисел як рядків? Дякую!


Виявляється, це проблема, що стосується версії. Іноді витяг з бази даних MySql підтримуватиме правильні типи. У старих версіях він може повертати все як рядок. Я писав про це сьогодні вранці. shakyshane.com/blog/output-json-from-php.html
Shane

1
У мене виникло те саме питання, і мені вдалося вирішити шахту за допомогою мутаторів Ларавеля в моделі. Це дозволяє змінювати значення в моделі. laravel.com/docs/eloquent#accessors-and-mutators Спочатку я не дуже зрозумів, але це питання допомогло: stackoverflow.com/questions/16985656/…
Jazzy

Відповіді:


28

Я зробив дуже швидкий тест:

$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 може зацікавити і вас, btw?


Дякую, Мартіне. Я використовую 5.2.9. Цікаво, чи чисельні дані читаються з db як рядок? Я впевнений, що типи полів є цілими, але я не можу придумати іншого пояснення. Я спробую ваш швидкий тест на моїй системі і побачу, чи отримаю такий самий результат.
Кріс Барнхілл

12
ОК близько 5.2.9; якщо ваші дані надходять із бази даних, проблема може бути в цьому: я часто бачив, як дані надходять із бази даних із усім, що передано на рядок (я бачив це з PDO та mssql; але, якщо я пам'ятаю правильно, це теж відбувається для MySQL в PHP <5.3, коли нового драйвера mysqlnd ще не було) ;; щоб перевірити, як виглядають ваші дані, ви можете використовувати var_dump, який виводить типи кожної частини даних.
Паскаль MARTIN

(продовження) вважає, що тип даних для числових значень є рядковим? Будь-які ідеї?
Кріс Барнхілл

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

Не має значення, що числові дані, повернені json_encode (), не містяться в лапках, це все-таки рядок. Повернене значення функції json_encode () - це рядок. Що стосується повернення MySQL усіх полів у вигляді рядків, так, я також стикався з цим спеціально з PDO. Я вважаю, що ви завжди повинні вводити в PHP значення, які, на вашу думку, будуть числовими цілими числами (або плавають), щоб переконатися, що не довіряйте MySQL або будь-якій іншій базі даних, щоб повертати значення з правильним типом.
Річард Ноп

352

Зауважте, що оскільки PHP 5.3.3 є прапор для автоматичного перетворення чисел (параметр параметрів доданий у PHP 5.3.0):

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

4
Зауважте, що JSON_NUMERIC_CHECK вимагає PHP 5.3.3.
Роберт

10
Працював ідеально, поки він не кинув числову мітку цілому числу, підірвавши .toLowerCase () в IE. Будьте уважні, це рішення просте, але надмірно ретельне.
Бред Кох

6
ВИ МОЄМО ГЕРОЙ це подобається.
Петрогад

5
Це має деякий побічний ефект, якщо ваш рядок не є числом, але таким є вміст: 5252788e16597. довідка: bugs.php.net/bug.php?id=64695
TonyQ

20
JSON_NUMERIC_CHECKнамагається автоматично відгадати, чи є рядок чисельним чи ні, намагаючись розібрати його. Це досить ненадійно, якщо задуматися. Він перетворить усі числові властивості в цифри (не тільки ті, що вам потрібно), і це зробить лише в тому випадку, якщо вони будуть схожі на числа. Це принаймні хитке, якщо не небезпечне. Код, який споживає вироблений JSON, може покладатися на тип або інший тип. Дивні речі можуть трапитися, якщо ці очікування не виправдаються. Якщо ви дбаєте про добрі практики та безпеку, вам слід вибірково перетворювати потрібні значення.
Вадим

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перетворює також номери телефонів та інші значення числових рядків, і це може спричинити проблеми з провідними нулями або "+" ... Я пропоную виправити цю проблему у функції зчитування БД.
цезарсол

8

спробуйте $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 скрап 6.0.5 з даними, що надходять з postgre db
Микола Спасов

7

Я зіткнувся з тією ж проблемою (PHP-5.2.11 / Windows). Я використовую цей спосіб вирішення

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

яке замінює всі (невід'ємні, цілі) числа, укладені в лапки, самим числом ("" 42 "стає" 42 ").

Дивіться також цей коментар у посібнику PHP .


Дякую за код, але, на жаль, він не працював на моєму json, тому що у мене є номер як ім'я об'єкта, і, здається, зробить json недійсним :(
SSH Це

@SSHTЦе може бути, ви повинні використовувати цей синтаксис для перетворення масиву в кодований JSON масив, а не в об'єкт. $json_array = json_encode($some_array, false);Таким чином, хибний аргумент говорить PHP не робити перетворення об'єкта.
Гайд

Зовсім не безпечно використовувати цей спосіб вирішення. Ви отримаєте недійсний 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 (тобто оточений подвійними лапками). Для його виправлення використовуйте постоянний тип (arr ["var"], "integer") або resype ($ 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>";

?>

2

Для повноти (оскільки я поки не можу додати коментарів), дозвольте також додати цю деталь як іншу відповідь:

(Редагувати. Читати після розуміння того, що вихідні дані (тобто у випадку ОП, набір результатів бази даних) можуть бути проблемою (шляхом повернення числових стовпців як рядків), а json_encode () насправді не є джерелом проблеми)

Сторінки вручну обох " mysql_fetch_array ":

Повертає масив рядків, який відповідає вилученому рядку,

... і " mysql_ fetch_ row ":

Повертає числовий масив рядків, який відповідає вилученому рядку

чітко стверджує, що; записи у поверненому масиві будуть рядками.

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

Не усвідомлюючи цього, я теж знайшов це питання і зрозумів проблему! :)

Як Паскаль Мартін заявив вище у своїх коментарях, які я вважаю, я вважаю, що рішення, яке стосується проблеми "неправильного типу" у джерелі (тобто, використовуючи функцію " mysql_field_type () " та виконуючи кастинг відразу після отримання, (або інші методи отримання, такі як "об'єкт"?)) були б кращими в цілому.


2

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

Я замінив php-mysql на php-mysqlnd, і проблема пішла. Числа - це числа, рядки - це рядки, булеві - булеві.


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, оскільки він автоматично виправить це
Erick

-2

json_encode серіалізує деяку структуру даних у форматі JSON для надсилання через мережу. Тому весь вміст буде мати тип рядка. Як і коли ви отримуєте якийсь параметр від $ _POST або $ _GET.

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


це не те, про що він говорить. він говорить про json, що має подвійні лапки навколо цифр.
JasonWoof

У випадку JSON він зберігає типи. Уявіть, що виписуєте буквальний JavaScript-об’єкт, будь-які котирувані значення стають рядками, а нецитуються числа стають цілими числами, 0x [0-9a-z] стає шістнадцятковою тощо. Існують різниці типів з PHP, наприклад, немає такого поняття, як асоціативний масив, просто Об'єкти або індексовані масиви тощо
bucabay

правильно. Проблема у нього полягала в тому, що він мав змінну php, яку, на його думку, мав тип int, оскільки він походить із стовпця DB типу 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

Лише коментар: він друкується слабко, все-таки результат "1" +1 буде ... 11 - тому, використовуючи JS, ви повинні бути уважнішими, ніж у мовах сильного типу, тому що вони будуть попереджати вас, JS просто робить те, що це
вважайте, що

Так, але це не суть, json_encode не повинен додавати лапки в числові поля.
andreszs

-3

Як сказав oli_arborum, я думаю, що ви можете використовувати preg_replaceдля виконання роботи. Просто змініть команду так:

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