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
ฉันมีปัญหาเดียวกันและฉันสามารถแก้ปัญหาของฉันโดยใช้ Mutators ของ Laravel ในโมเดล มันช่วยให้คุณปรับเปลี่ยนค่าในรูปแบบ 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/อาจเกี่ยวข้องกัน ตัวอย่างเช่นBug # 40503: การแปลงจำนวนเต็ม json_encode ไม่สอดคล้องกับ PHP ?


บางทีBug # 38680ก็สนใจคุณเหมือนกัน btw?


ขอบคุณมาร์ติน ฉันใช้ 5.2.9 ฉันสงสัยว่าข้อมูลตัวเลขกำลังอ่านจาก db เป็นสตริงหรือไม่? ฉันแน่ใจว่าประเภทเขตข้อมูลมีความรุนแรง แต่ฉันไม่สามารถนึกถึงคำอธิบายอื่นได้ ฉันจะลองทดสอบอย่างรวดเร็วของคุณในระบบของฉันและดูว่าฉันได้รับผลลัพธ์เดียวกัน
Chris Barnhill

12
ตกลงประมาณ 5.2.9; หากข้อมูลของคุณมาจากฐานข้อมูลปัญหาอาจเกิดขึ้นที่นั่น: ฉันมักจะเห็นข้อมูลมาจากฐานข้อมูลที่มีทุกสิ่งในสตริง (ฉันเคยเห็นสิ่งนี้กับ PDO และ mssql แต่ถ้าฉันจำได้ถูกต้องสิ่งนี้ก็เกิดขึ้นเช่นกัน สำหรับ MySQL ใน PHP <5.3 เมื่อไดรเวอร์ mysqlnd ใหม่ยังไม่มีอยู่) ;; เพื่อตรวจสอบว่าข้อมูลของคุณเป็นอย่างไรคุณสามารถใช้ var_dump ซึ่งแสดงประเภทของข้อมูลแต่ละส่วน
Pascal MARTIN

(ต่อ) คิดว่าประเภทข้อมูลสำหรับค่าตัวเลขเป็นสตริงหรือไม่ ความคิดใด ๆ
Chris Barnhill

1
ฉันไม่ทราบเหตุผลทางเทคนิคของ "ทำไมข้อมูลถูกส่งคืนจาก MySQL เป็นสตริง" ;; อาจเป็นสิ่งที่เกี่ยวข้องกับไดรเวอร์ระหว่าง PHP และ MySQL ;; นั่นคือสิ่งที่ (อย่างน้อยในบางกรณี) แก้ไขโดยไดรเวอร์ mysqlnd ใหม่ที่มาพร้อมกับ PHP 5.3 (ดูblog.ulf-wendel.de/?p=184ค้นหา "จำนวนเต็ม" ในหน้าเพื่อค้นหาสิ่งที่น่าสนใจ ประโยค) ;; แต่ผมเห็นว่าเรื่องนี้ไม่ดี ^^
ปาสคาลมาร์ติน

ไม่สำคัญว่าข้อมูลตัวเลขที่ส่งกลับโดย json_encode () ไม่ได้อยู่ในเครื่องหมายคำพูด แต่ก็ยังคงเป็นสตริง ค่าส่งคืนของฟังก์ชัน json_encode () คือสตริง เกี่ยวกับ MySQL ที่คืนค่าเขตข้อมูลทั้งหมดเป็นสตริงใช่ฉันยังพบสิ่งนี้โดยเฉพาะกับ PDO วิธีที่ฉันเห็นคุณควรใช้ค่าที่คุณคาดว่าจะเป็นตัวเลขเป็นจำนวนเต็ม (หรือลอย) ใน PHP เพื่อให้แน่ใจว่าไม่เชื่อถือ MySQL หรือฐานข้อมูลอื่น ๆ เพื่อคืนค่าด้วยชนิดที่ถูกต้อง
Richard Knop

352

โปรดทราบว่าตั้งแต่ 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"}

4
โปรดทราบว่า JSON_NUMERIC_CHECK ต้องการ PHP 5.3.3
Robert

10
ทำงานได้สมบูรณ์แบบจนกว่าจะส่งเลเบลตัวเลขไปที่จำนวนเต็ม, .toLowerCase () ใน IE ระวังวิธีแก้ปัญหานี้เรียบง่าย แต่ไร้ประสิทธิภาพ
แบรดโคช์

6
คุณคือฮีโร่ของฉันรักมัน
Petrogad

5
มันมีผลข้างเคียงบางอย่างถ้าสตริงของคุณไม่ได้เป็นตัวเลข แต่เนื้อหาเช่นนี้: 5252788e16597 อ้างอิง: bugs.php.net/bug.php?id=64695
TonyQ

20
JSON_NUMERIC_CHECKพยายามที่จะคาดเดาโดยอัตโนมัติถ้าสตริงเป็นตัวเลขหรือไม่โดยพยายามแยกมัน มันค่อนข้างไม่น่าเชื่อถือถ้าคุณคิดเกี่ยวกับมัน มันจะแปลงทุกคุณสมบัติที่เป็นตัวเลขที่มองไปยังหมายเลข (ไม่เพียง แต่ผู้ที่คุณต้องการ) และมันจะทำอย่างนั้น แต่ถ้าพวกเขาดูเหมือนเป็นตัวเลข อย่างน้อยก็สั่นหากไม่ปลอดภัย รหัสที่ใช้ JSON ที่ผลิตอาจขึ้นอยู่กับประเภทที่เป็นหนึ่งหรืออื่น ๆ สิ่งแปลก ๆ สามารถเกิดขึ้นได้หากไม่ได้รับความคาดหวังเหล่านั้น หากคุณใส่ใจเกี่ยวกับแนวปฏิบัติที่ดีและความปลอดภัยคุณควรเลือกแปลงค่าที่คุณต้องการ
Wadim

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}

ใช่ดูเหมือนว่าปัญหาของอะแดปเตอร์ DB ซึ่งไม่ตีความชนิดข้อมูลไม่ใช่json_encodeฟังก์ชัน นี่เป็นคำตอบที่ถูกต้องที่สุด แต่ต้องระวังเนื่องจากJSON_NUMERIC_CHECKแปลงหมายเลขโทรศัพท์และค่าสตริงตัวเลขอื่น ๆ ด้วยและสิ่งนี้อาจทำให้เกิดปัญหาในศูนย์นำหน้าหรือ '+' ... ฉันขอแนะนำให้แก้ไขปัญหานี้ในฟังก์ชันการอ่าน DB
caesarsol

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 บนเดเบียนบีบ 6.0.5 พร้อมข้อมูลที่มาจาก postgre db
Nikolay Spassov

7

ฉันพบปัญหาเดียวกัน (PHP-5.2.11 / Windows) ฉันใช้วิธีแก้ปัญหานี้

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

ซึ่งจะแทนที่ตัวเลขทั้งหมด (ไม่ใช่ลบจำนวนเต็ม) ที่อยู่ในเครื่องหมายคำพูดด้วยตัวเลข ('"42"' จะกลายเป็น '42')

ดูเพิ่มเติมความคิดเห็นนี้ในคู่มือ PHP


ขอบคุณสำหรับรหัส แต่น่าเศร้าที่มันไม่ทำงานบน json ของฉันเพราะฉันมีจำนวนเป็นชื่อวัตถุและดูเหมือนว่าจะทำให้ json ไม่ถูกต้อง :(
SSH

@SSH นี่บางทีคุณควรใช้ไวยากรณ์นี้เพื่อแปลงอาร์เรย์เป็นอาร์เรย์ที่เข้ารหัส JSON ไม่ใช่วัตถุ $json_array = json_encode($some_array, false);ดังนั้นอาร์กิวเมนต์ที่ผิดพลาดบอกให้ PHP ไม่ทำการแปลงวัตถุ
hyde

ไม่ปลอดภัยเลยที่จะใช้วิธีแก้ปัญหานั้น คุณจะได้รับ json ที่ไม่ถูกต้องพร้อมโครงสร้างดังนี้:json_encode(array(-1=>'que', '0'=>'-1'))
Alex Yaroshevich

ฉันมีปัญหาในทางกลับกันฉันต้องการจำนวนเต็มของฉันที่เข้ารหัสเป็นสตริงใน PHP 7.0 และใช้สิ่งนี้$this->data = preg_replace("/\" *?: *?(\d+)/", '":"$1"', $this->data);
Maciej Swic

ฉันจะเปลี่ยน regex ดั้งเดิมเป็น `" /\"(\d+\.?\d*)\"/ "" เพื่อรวมทศนิยมอีกคนหนึ่งคือผู้ชายที่ใช้ JSON_NUMERIC_CHECK จะพบปัญหาเมื่อสตริงนั้นยังถูกต้อง จำนวนในสัญกรณ์ทางวิทยาศาสตร์ เช่น 19E008 JSON_NUMERIC_CHECK จะแปลงเป็น 190000 ...
Sahib Khan

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>";

?>

2

เพื่อความสมบูรณ์ (เนื่องจากฉันยังไม่สามารถเพิ่มความคิดเห็น) ให้ฉันเพิ่มรายละเอียดนี้เป็นคำตอบอื่น:

(แก้ไข: หากต้องการอ่านหลังจากตระหนักว่าข้อมูลต้นฉบับ (เช่นในกรณีของ OP ชุดผลลัพธ์ฐานข้อมูล) อาจเป็นปัญหา (โดยการส่งคืนคอลัมน์ตัวเลขเป็นสตริง) และ json_encode () อันที่จริงไม่ใช่แหล่งที่มาของปัญหา)

หน้าคู่มือของทั้ง " mysql_fetch_array ":

ส่งกลับอาร์เรย์ของสตริงที่สอดคล้องกับแถวดึง

... และ " mysql_ fetch_ แถว ":

ส่งคืนอาร์เรย์ตัวเลขของสตริงที่สอดคล้องกับแถวดึงข้อมูล

ระบุอย่างชัดเจนว่า รายการในอาร์เรย์ที่ส่งคืนจะเป็นสตริง

(ฉันใช้คลาส DB ใน phpBB2 (ใช่ฉันรู้ว่ามันล้าสมัยแล้ว) และ "sql_fetchrow ()" เมธอดของคลาสนั้นใช้ "mysql_fetch_array ()")

ไม่ทราบว่าฉันจบลงด้วยการค้นหาคำถามนี้และเข้าใจปัญหา! :)

ในฐานะที่เป็น Pascal Martin ที่ระบุไว้ข้างต้นในการแสดงความคิดเห็นการติดตามของเขาผมเชื่อว่าวิธีการแก้ปัญหา "ประเภทที่ไม่ถูกต้อง" ที่แหล่งที่มา (เช่นโดยการใช้ฟังก์ชั่น" mysql_field_type () " วิธีการดึงข้อมูลอื่น ๆ เช่น "วัตถุ"?)) จะดีกว่าโดยทั่วไป


2

ดังนั้นPascal MARTINไม่ได้รับเครดิตเพียงพอที่นี่ การตรวจสอบค่าตัวเลขในทุก ๆ การส่งคืน JSON นั้นไม่สามารถทำได้สำหรับโครงการที่มีอยู่ซึ่งมีฟังก์ชั่นด้านเซิร์ฟเวอร์หลายร้อยรายการ

ฉันแทนที่ php-mysql ด้วย php-mysqlnd และปัญหาก็หายไป ตัวเลขคือตัวเลขสตริงเป็นสตริงบูลีนเป็นบูลีน


0

ฉันยังมีปัญหาการประมวลผลข้อมูลเดียวกันจากฐานข้อมูล โดยทั่วไปปัญหาคือประเภทในอาร์เรย์ที่จะแปลงใน json ได้รับการยอมรับจาก PHP เป็นสตริงและไม่เป็นจำนวนเต็ม ในกรณีของฉันฉันทำแบบสอบถามที่ส่งคืนข้อมูลจากแถวนับคอลัมน์ DB ไดรเวอร์ PDO ไม่รู้จักคอลัมน์เป็น int แต่เป็นสตริง ฉันแก้ไขด้วยการแสดงเป็น 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 มันจะอนุรักษ์ประเภท ลองนึกภาพการเขียนจาวาสคริปต์อ๊อบเจคตัวอักษรค่าที่อ้างอิงใด ๆ กลายเป็นสตริง แต่ตัวเลขที่ไม่ได้อ้างอิงกลายเป็นจำนวนเต็ม 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

ขอบคุณ ฉันหวังว่าจะมีวิธีการที่หรูหรากว่านี้
Chris Barnhill

1
ใช่วิธีที่ปลอดภัยที่สุดคือการแยกวิเคราะห์พวกเขา แต่อีกครั้งจาวาสคริปต์ไม่พิมพ์อย่างหลวม ๆ หรือ
mauris

เพียงความคิดเห็น: มันถูกพิมพ์อย่างหลวม ๆ แต่ผลลัพธ์ของ "1" +1 จะเป็น ... 11 - ดังนั้นการใช้ JS คุณควรจะใส่ใจมากกว่าภาษาที่ใช้ภาษาอื่นเพราะพวกเขาจะเตือนคุณ JS ทำสิ่งที่มันเป็น คิดว่าดีที่สุดดีที่สุดถ้าจัดการ String-เบอร์ ...
SamiSalami

ใช่ แต่นั่นไม่ใช่จุด json_encode ไม่ควรเพิ่มเครื่องหมายคำพูดในฟิลด์ตัวเลข
andreszs

-3

อย่างที่ oli_arborum พูดฉันคิดว่าคุณสามารถใช้ a preg_replaceในการทำงานได้ เพียงแค่เปลี่ยนคำสั่งเช่นนี้:

$json = preg_replace('#:"(\d+)"#', ':$1', $json);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.