PHP json_encode数値を文字列としてエンコード


142

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/...を
ジャジー

回答:


28

私は非常に簡単なテストを行いました:

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

私が間違っていなければ、これはあなたが説明しているように思えますか?

そして、私は出力として得ています:

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

したがって、この場合、整数は文字列に変換されていません。


それでも、これは使用しているPHPのバージョンに依存している可能性があります。PHPのバージョンに応じて、json_encodeに関連するいくつかのバグが修正されています...

このテストはPHP 5.2.6で行われました。PHP 5.2.9と5.3.0でも同じ結果が得られます。テストする別の5.2.xバージョンはありませんが、:-(

PHPのどのバージョンを使用していますか?それとも、あなたのテストケースはあなたが投稿した例よりも複雑ですか?

多分1つのバグレポート http://bugs.php.net/が関連している可能性がありますか?たとえば、Bug#40503:json_encode整数変換がPHPと矛盾していますか?


たぶんバグ#38680もあなたに興味がありますか?


マーティン、ありがとう。5.2.9を使用しています。数値データがデータベースから文字列として読み取られているのでしょうか?フィールドタイプがintであると確信していますが、別の説明は考えられません。私のシステムでクイックテストを試して、同じ結果が得られるかどうかを確認します。
Chris Barnhill

12
約5.2.9です。データがデータベースからのものである場合、問題がある可能性があります。データがデータベースからのもので、すべてが文字列にキャストされているのをよく見ました(これをPDOとmssqlで見たことがありますが、正しく覚えていれば、これも起こります)新しいmysqlndドライバーがまだ存在しない場合のPHP <5.3のMySQLの場合);; データがどのように見えるかを確認するには、データの各部分のタイプを出力するvar_dumpを使用できます。
Pascal MARTIN

(続き)数値のデータ型は文字列だと思いますか?何か案は?
Chris Barnhill、

1
「データがMySQLから文字列として返される理由」の技術的な理由は正確にはわかりません;; おそらく、PHPとMySQLの間のドライバに関係するものです;; これは、PHP 5.3に付属する新しいmysqlndドライバー(blog.ulf-wendel.de/?p=184を参照)によって(少なくとも一部の場合は)修正されるものです。ページで「integer」を検索して、興味深いものを見つけてください。文);; しかし、これは良くないことだと思います^^
Pascal MARTIN

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
数値ラベルを整数にキャストし、IEで.toLowerCase()を爆破するまで完璧に機能しました。注意してください、このソリューションは単純ですが熱狂的です。
Brad Koch

6
あなたは私のヒーローです。
Petrogad 2012

5
文字列が数値ではなくコンテンツ5252788e16597である場合、いくつかの副作用があります。参照:bugs.php.net/bug.php
id

20
JSON_NUMERIC_CHECK文字列を解析しようとして、文字列が数値かどうかを自動的に推測しようとします。あなたがそれについて考えるならば、それはかなり信頼できません。数値のように見えるすべてのプロパティを(必要なプロパティだけでなく)数値に変換し数値のように見える場合にのみそれを行います。安全ではないにしても、それは少なくとも不安定です。生成されたJSONを使用するコードは、どちらか一方のタイプに依存する場合があります。これらの期待が満たされない場合、奇妙なことが起こります。適切な方法と安全性を重視する場合は、必要な値を選択的に変換する必要があります。
ワディム2014

35

私も同様にDB(PostgreSQL)から読み込んでおり、すべて文字列でした。各行をループし、それを使って最終的な結果配列を構築するため、

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

ループ内で強制的に整数値にします。これを行うjson_encode($result_arr)と、数値として正しくフォーマットされます。これにより、データベースからの数字とそうでない数字を制御できます。

編集:

このjson_encode()関数には、JSON_NUMERIC_CHECKフラグを2番目の引数として使用して、その場でこれを実行する機能もあります。ドキュメントのこのユーザーの例に示されているように(下にコピー)、それを使用する場合は注意が必要です。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関数ではなく、データ型を解釈しないDBアダプターにあるようです。これが最も正しい答えですが、JSON_NUMERIC_CHECK電話番号やその他の数値文字列値も変換するので注意してください。これにより、先行ゼロまたは「+」に問題が発生する可能性があります... DB読み取り機能でこの問題を修正することをお勧めします。
caesarsol 2014年


7

同じ問題が発生しています(PHP-5.2.11 / Windows)。この回避策を使用しています

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

引用符で囲まれたすべての(非負の整数)数値を数値自体に置き換えます( '"42"'は '42'になります)。

PHPマニュアルのこのコメントも参照してください。


コードをありがとうございましたが、残念ながら、オブジェクト名として数字を使用しているため、jsonでは機能しませんでした。jsonが無効になるようです:(
SSH This

@SSHこれは、おそらくこの構文を使用して、配列をオブジェクトではなくJSONエンコードされた配列に変換する必要があります。$json_array = json_encode($some_array, false);したがって、false引数はPHPにオブジェクト変換を行わないように指示します。
hyde

その回避策を使用することは、まったく安全ではありません。:あなたはそのような構造で、無効なJSONを取得しますjson_encode(array(-1=>'que', '0'=>'-1'))
アレックスYaroshevich

逆の問題がありました$this->data = preg_replace("/\" *?: *?(\d+)/", '":"$1"', $this->data);
。PHP7.0で

元の正規表現を `" /\"(\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_ row ":

フェッチされた行に対応する文字列の数値配列を返します

明確に述べている; 返される配列のエントリは文字列になります。

(私はphpBB2でDBクラスを使用していました(そうです、それは廃止されました!)、そしてそのクラスの "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としてキャストを実行することで解決しました。


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


-1

同じ問題が発生し、データベースが値を文字列として返していました。

これを回避策として使用します。

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

つまり、値を1倍して数値にキャストします

誰かを助けることを願っています


乗算器の使用は、最も効率的なソリューションではありません。json_encodeでJSON_NUMERIC_CHECKを使用することを検討してください。自動的に修正されます
Erick

-2

json_encodeは、データ構造をJSON形式でシリアル化し、ネットワーク経由で送信します。したがって、すべてのコンテンツは文字列型になります。$ _POSTまたは$ _GETからパラメーターを受け取るときと同じです。

送信された値に対して数値演算を行う必要がある場合は、まずそれらをintに変換し PHPのintval()関数またはJavascriptのparseInt()を使用)、次に演算を実行します。


それは彼が話していることではありません。彼は、jsonが数字を二重引用符で囲んでいることについて話している。
JasonWoof

JSONの場合、タイプを保存します。リテラルJavaScriptオブジェクトを書き込むと想像してください。引用符で囲まれた値は文字列になりますが、引用符で囲まれていない数値は整数になり、0x [0-9a-z]は16進数になります。PHPには型の違いがあります。たとえば、連想配列、単なるオブジェクトやインデックス付き配列など
bucabay

正しい。彼が抱えていた問題は、php変数があり、int型のDB列から来たため、int型であると考えていたということでした。しかし、実際にはPHP変数には文字列型があり、JSONの引用符でした。
JasonWoof 2009

-2

PHP json_encode()は文字列を返します。

ただし、jsコードでparseFloat()またはparseInt()を使用できます。

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

ありがとう。もっとエレガントな方法があるといいのですが。
Chris Barnhill、

1
そうです、最も安全な方法はそれらを解析することです。しかし、繰り返しになりますが、JavaScriptは緩やかに型付けされていませんか?
モーリス2009

ただのコメント:それは緩やかに型付けされていますが、それでも「1 + 1」の結果は... 11-したがって、JSを使用すると、強い型言語よりも注意が必要です。 String-Numbersを処理する場合に最適だと思います...
SamiSalami

はい、しかしそれは重要ではありません。json_encodeは数値フィールドに引用符を追加するべきではありません。
andreszs 2015年

-3

oli_arborumが言ったように、私はあなたがpreg_replace仕事をするために使うことができると思います。次のようにコマンドを変更するだけです。

$json = preg_replace('#:"(\d+)"#', ':$1', $json);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.