PHP mã hóa json_encode dưới dạng chuỗi


142

Tôi gặp một vấn đề với hàm json_encode PHP. Nó mã hóa số dưới dạng chuỗi, vd

array('id' => 3)

trở thành

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

Khi js gặp các giá trị này, nó diễn giải chúng là các chuỗi và các hoạt động số không thành công trên chúng. Có ai biết một số cách để ngăn chặn json_encodemã hóa số dưới dạng chuỗi không? Cảm ơn bạn!


Nó chỉ ra rằng đây là một vấn đề cụ thể phiên bản. Đôi khi một thao tác kéo từ cơ sở dữ liệu MySql sẽ duy trì các loại chính xác. Trong các phiên bản cũ hơn, nó có thể trả về mọi thứ dưới dạng chuỗi. Tôi đã viết về nó sáng nay. shakyshane.com/blog/output-json-from-php.html
shane

1
Tôi đã có cùng một vấn đề và tôi đã có thể giải quyết vấn đề của mình bằng cách sử dụng Mutators của Laravel trong Mô hình. Nó cho phép bạn sửa đổi các giá trị trong mô hình. laravel.com/docs/eloquent#accessors-and-mutators Tôi không hoàn toàn nhận được nó lúc đầu, nhưng câu hỏi này giúp: stackoverflow.com/questions/16985656/...
Jazzy

Câu trả lời:


28

Tôi đã thực hiện một bài kiểm tra rất nhanh:

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

Điều này có vẻ giống như những gì bạn mô tả, nếu tôi không nhầm?

Và tôi đang nhận được như là đầu ra:

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

Vì vậy, trong trường hợp này, các số nguyên chưa được chuyển đổi thành chuỗi.


Tuy nhiên, điều này có thể phụ thuộc vào phiên bản PHP mà chúng tôi đang sử dụng: đã có một vài lỗi liên quan đến json_encode được sửa, tùy thuộc vào phiên bản PHP ...

Thử nghiệm này đã được thực hiện với PHP 5.2.6; Tôi đang nhận được điều tương tự với PHP 5.2.9 và 5.3.0; Tôi không có phiên bản 5.2.x khác để thử nghiệm, mặc dù :-(

Phiên bản PHP nào bạn đang sử dụng? Hoặc là trường hợp thử nghiệm của bạn phức tạp hơn ví dụ bạn đã đăng?

Có lẽ một báo cáo lỗi trên http://bugs.php.net/ có thể liên quan? Chẳng hạn, Bug # 40503: json_encode chuyển đổi số nguyên không phù hợp với PHP ?


Có lẽ Bug # 38680 cũng có thể khiến bạn quan tâm, btw?


Cảm ơn Martin. Tôi đang sử dụng 5.2.9. Tôi tự hỏi nếu dữ liệu số được đọc từ db dưới dạng chuỗi? Tôi chắc chắn các loại trường là int, nhưng tôi không thể nghĩ ra lời giải thích khác. Tôi sẽ thử kiểm tra nhanh trên hệ thống của tôi và xem liệu tôi có nhận được kết quả tương tự không.
Chris Bar dốc

12
OK khoảng 5.2.9; nếu dữ liệu của bạn đến từ cơ sở dữ liệu, vấn đề có thể xảy ra: Tôi thường thấy dữ liệu đến từ cơ sở dữ liệu với mọi thứ được đúc thành chuỗi (Tôi đã thấy điều này với PDO và mssql; nhưng, nếu tôi nhớ chính xác, điều này cũng xảy ra cho MySQL trong PHP <5.3, khi trình điều khiển mysqlnd mới chưa tồn tại) ;; để kiểm tra dữ liệu của bạn trông như thế nào, bạn có thể sử dụng var_dump, đầu ra các loại của từng phần của dữ liệu.
Pascal MARTIN

(tiếp theo) nghĩ rằng kiểu dữ liệu cho các giá trị số là chuỗi? Có ý kiến ​​gì không?
Chris Bar dốc

1
Tôi không biết chính xác lý do kỹ thuật "tại sao dữ liệu được trả về từ MySQL dưới dạng chuỗi" ;; có lẽ phải làm gì đó với trình điều khiển giữa PHP và MySQL ;; đó là một cái gì đó (ít nhất là trong một số trường hợp) được sửa bởi trình điều khiển mysqlnd mới đi kèm với PHP 5.3 (xem blog.ulf-wendel.de/?p=184 ; tìm kiếm "số nguyên" trong trang để tìm thấy sự thú vị kết án) ;; nhưng tôi đồng ý rằng điều này không tốt ^^
Pascal MARTIN

Không có vấn đề gì khi dữ liệu số được trả về bởi json_encode () không nằm trong dấu ngoặc kép, nó vẫn là một chuỗi. Giá trị trả về của hàm json_encode () là một chuỗi. Về việc MySQL trả về tất cả các trường dưới dạng chuỗi, vâng tôi cũng đã gặp điều này đặc biệt với PDO. Theo cách tôi thấy, bạn phải luôn truyền các giá trị mà bạn mong đợi thành số nguyên (hoặc float) trong PHP để đảm bảo, không tin tưởng MySQL hoặc bất kỳ cơ sở dữ liệu nào khác để trả về các giá trị với loại chính xác.
Richard Knop

352

Lưu ý rằng kể từ PHP 5.3.3, có một cờ cho các số tự động chuyển đổi (tham số tùy chọn đã được thêm vào trong PHP 5.3.0):

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

4
Lưu ý rằng JSON_NUMERIC_CHECK yêu cầu PHP 5.3.3.
Robert

10
Hoạt động hoàn hảo cho đến khi nó tạo nhãn số thành số nguyên, làm nổ tung .toLowerCase () trong IE. Hãy cẩn thận, giải pháp này là đơn giản nhưng quá nhiệt tình.
Brad Koch

6
BẠN LÀ ANH HÙNG CỦA TÔI yêu nó.
Petrogad

5
Nó có một số tác dụng phụ nếu chuỗi của bạn không phải là số mà là nội dung như thế này: 5252788e16597. tham khảo: bug.php.net/orms.php?id=64695
TonyQ

20
JSON_NUMERIC_CHECKcố gắng tự động đoán xem một chuỗi có phải là số hay không bằng cách cố phân tích cú pháp. Điều đó là không đáng tin cậy nếu bạn nghĩ về nó. Nó sẽ chuyển đổi tất cả các thuộc tính tìm kiếm số thành số (không chỉ những thuộc tính bạn muốn) và nó sẽ làm điều đó chỉ khi chúng trông giống như số. Điều đó ít nhất là run rẩy nếu không an toàn. Mã tiêu thụ JSON được sản xuất có thể dựa vào loại là loại này hoặc loại kia. Những điều kỳ lạ có thể xảy ra nếu những mong muốn đó không được đáp ứng. Nếu bạn quan tâm đến các thực hành tốt và an toàn, bạn nên chuyển đổi có chọn lọc các giá trị bạn muốn.
wadim

35

Tôi, tương tự như vậy đã đọc từ một DB (PostgreSQL) và mọi thứ là một chuỗi. Chúng tôi lặp qua từng hàng và làm mọi thứ với nó để xây dựng mảng kết quả cuối cùng của chúng tôi, vì vậy tôi đã sử dụng

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

trong vòng lặp để buộc nó là một giá trị nguyên. Khi tôi làm json_encode($result_arr)bây giờ, nó định dạng chính xác nó như là một số. Điều này cho phép bạn kiểm soát những gì và không phải là một số đến từ cơ sở dữ liệu của bạn.

BIÊN TẬP:

Các json_encode()chức năng cũng có khả năng để làm điều này một cách nhanh chóng bằng cách sử dụng JSON_NUMERIC_CHECKlá cờ như một đối số thứ hai với nó. Bạn cần cẩn thận khi sử dụng nó mặc dù như trong ví dụ về người dùng này trong tài liệu (được sao chép bên dưới): http://uk3.php.net/manual/en/feft.json-encode.php#106641

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

Và sau đó bạn nhận được JSON này:

{"phone_number":33123456789}

đúng, có vẻ như vấn đề là của bộ điều hợp DB không giải thích các kiểu dữ liệu, KHÔNG phải của json_encodehàm. đây là câu trả lời đúng nhất, nhưng hãy cẩn thận vì JSON_NUMERIC_CHECKcũng chuyển đổi số điện thoại và các giá trị chuỗi số khác và điều này có thể gây ra vấn đề trong việc dẫn số 0 hoặc '+' ... Tôi khuyên bạn nên sửa vấn đề này trong chức năng đọc DB.
caesarsol


7

Tôi đang gặp vấn đề tương tự (PHP-5.2.11 / Windows). Tôi đang sử dụng cách giải quyết này

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

thay thế tất cả các số (không âm, số nguyên) được đặt trong dấu ngoặc kép bằng chính số đó ('"42"' trở thành '42').

Xem thêm bình luận này trong hướng dẫn sử dụng PHP .


Cảm ơn mã, nhưng thật đáng buồn là nó không hoạt động trên json của tôi vì tôi có một số làm tên đối tượng và dường như nó khiến json không hợp lệ :(
SSH This

@SSHThis, có lẽ bạn nên sử dụng cú pháp này để chuyển đổi mảng thành mảng được mã hóa JSON chứ không phải là một đối tượng. $json_array = json_encode($some_array, false);Vì vậy, đối số sai bảo PHP không thực hiện chuyển đổi đối tượng.
hyde

Không an toàn chút nào khi sử dụng cách giải quyết đó. Bạn sẽ nhận được json không hợp lệ với các cấu trúc như thế:json_encode(array(-1=>'que', '0'=>'-1'))
Alex Yaroshevich

Tôi đã gặp một vấn đề theo cách khác, tôi cần số nguyên của mình được mã hóa dưới dạng chuỗi trong PHP 7.0 và đã sử dụng điều này$this->data = preg_replace("/\" *?: *?(\d+)/", '":"$1"', $this->data);
Maciej Swic

Tôi sẽ thay đổi regex ban đầu thành `" /\"(\d+\.?\d*)\"/ "` để bao gồm số thập phân, một lưu ý khác là những kẻ sử dụng JSON_NUMERIC_CHECK sẽ gặp phải vấn đề khi một chuỗi cũng đúng số trong ký hiệu khoa học. ví dụ: 19E008. JSON_NUMERIC_CHECK sẽ chuyển đổi nó thành 190000 ...
Sahib Khan

3

Thử nghiệm sau đây xác nhận rằng việc thay đổi loại thành chuỗi khiến json_encode () trả về một số dưới dạng chuỗi JSON (nghĩa là được bao quanh bởi dấu ngoặc kép). Sử dụng settype (Array ["var"], "số nguyên") hoặc settype ($ Array ["var"], "float") để sửa nó.

<?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

Để hoàn thiện (vì tôi chưa thể thêm nhận xét), tôi cũng thêm chi tiết này dưới dạng câu trả lời khác:

(Chỉnh sửa: Để được đọc sau khi nhận ra rằng dữ liệu nguồn (nghĩa là trong trường hợp của OP, tập kết quả cơ sở dữ liệu) có thể là vấn đề (bằng cách trả về các cột số dưới dạng chuỗi) và thực tế json_encode () không phải là nguồn của vấn đề)

Các trang hướng dẫn của cả " mysql_fetch_array ":

Trả về một chuỗi các chuỗi tương ứng với hàng được tìm nạp,

... và " mysql_ fetch_ hàng ":

Trả về một chuỗi các chuỗi tương ứng với hàng được tìm nạp

nói rõ rằng; các mục trong mảng trả về sẽ là chuỗi.

(Tôi đã sử dụng lớp DB trong phpBB2 (vâng tôi biết, nó đã lỗi thời!) Và phương thức "sql_fetchrow ()" của lớp đó sử dụng "mysql_fetch_array ()")

Không nhận ra điều đó, cuối cùng tôi cũng tìm thấy câu hỏi này và hiểu vấn đề! :)

Như Pascal Martin đã nêu ở trên trong các bình luận tiếp theo của mình, tôi tin rằng một giải pháp xử lý vấn đề "loại không chính xác" tại nguồn (tức là bằng cách sử dụng hàm " mysql_field_type () " và thực hiện truyền ngay sau khi tìm nạp, (hoặc các phương thức tìm nạp khác như "object"?)) nói chung sẽ tốt hơn.


2

Vì vậy, Pascal MARTIN không nhận đủ tín dụng ở đây. Việc kiểm tra các giá trị số trên mỗi lần trả về JSON là không khả thi đối với một dự án hiện có với hàng trăm chức năng phía máy chủ.

Tôi đã thay thế php-mysql bằng php-mysqlnd và vấn đề đã biến mất. Số là số, chuỗi là chuỗi, booleans là boolean.


0

Tôi cũng có vấn đề tương tự xử lý dữ liệu từ cơ sở dữ liệu. Về cơ bản vấn đề là loại trong mảng cần chuyển đổi trong json, được PHP nhận ra là một chuỗi chứ không phải là số nguyên. Trong trường hợp của tôi, tôi đã thực hiện một truy vấn trả về dữ liệu từ một hàng đếm cột DB. Trình điều khiển PDO không nhận ra cột là int, mà là chuỗi. Tôi đã giải quyết bằng cách thực hiện một vai như int trong cột bị ảnh hưởng.


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

0

Đó là phiên bản php, sự cố tương tự đã nâng cấp phiên bản php của tôi lên 5.6.


0

Đúc các giá trị cho một int hoặc float dường như để sửa nó. Ví dụ:

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

0

Bạn có thể sử dụng (int) nếu có vấn đề xảy ra !! Nó sẽ hoạt động tốt.


-1

Chỉ cần chạy vào cùng một vấn đề và cơ sở dữ liệu trả về các giá trị dưới dạng chuỗi.

Tôi sử dụng điều này như một cách giải quyết:

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

Đó là nhân giá trị với 1 để bỏ nó thành một số

Mong rằng sẽ giúp được ai đó


sử dụng hệ số nhân không phải là giải pháp hiệu quả nhất. xem xét sử dụng JSON_NUMERIC_CHECK trên json_encode vì nó sẽ tự động sửa nó
Erick

-2

json_encode tuần tự hóa một số cấu trúc dữ liệu ở định dạng JSON sẽ được gửi qua mạng. Do đó, tất cả nội dung sẽ thuộc loại chuỗi. Giống như khi bạn nhận được một số tham số từ $ _POST hoặc $ _GET.

Nếu bạn phải thực hiện các phép toán số trên các giá trị được gửi, chỉ cần chuyển đổi chúng thành int trước (với hàm intval () trong PHP hoặc parseInt () trong Javascript) và sau đó thực hiện các thao tác.


đó không phải là những gì anh ấy đang nói. ông đang nói về json có hai trích dẫn xung quanh các con số.
JasonWoust

Trong trường hợp JSON, nó bảo tồn các loại. Hãy tưởng tượng viết ra một Đối tượng JavaScript bằng chữ, mọi giá trị được trích dẫn đều trở thành chuỗi, nhưng các số không được trích dẫn trở thành số nguyên, 0x [0-9a-z] trở thành hex, v.v. một mảng kết hợp, chỉ các Đối tượng hoặc các mảng được lập chỉ mục, v.v.
bucabay

đúng. Vấn đề anh gặp phải là anh có biến php, mà anh nghĩ là có kiểu int, vì nó xuất phát từ cột DB kiểu int. Nhưng trên thực tế, biến PHP có chuỗi kiểu, do đó, các trích dẫn trong JSON.
JasonWoust

-2

Chà, PHP json_encode () trả về một chuỗi.

Bạn có thể sử dụng parseFloat () hoặc parseInt () trong mã js:

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

Cảm ơn. Tôi đã hy vọng có một phương pháp thanh lịch hơn.
Chris Bar dốc

1
yeah, cách an toàn nhất là phân tích chúng. nhưng một lần nữa, Javascript không được gõ một cách lỏng lẻo?
mauris

Chỉ là một nhận xét: Nó được gõ một cách lỏng lẻo, vẫn là kết quả của "1" +1 sẽ là ... 11 - vì vậy, sử dụng JS bạn nên chú ý hơn so với các ngôn ngữ loại mạnh, bởi vì chúng sẽ cảnh báo bạn, JS chỉ làm những gì nó nghĩ là tốt nhất nếu xử lý các chuỗi số ...
SamiSalami

Có nhưng đó không phải là vấn đề, json_encode không nên thêm dấu ngoặc kép vào các trường số.
andreszs

-3

Giống như oli_arborum đã nói, tôi nghĩ bạn có thể sử dụng một preg_replaceđể thực hiện công việc. Chỉ cần thay đổi lệnh như thế này:

$json = preg_replace('#:"(\d+)"#', ':$1', $json);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.