背景
json字符串的解析非常常見,但是php中單雙引號含義不同以及各種字符串處理函數對json字符串的處理常常會導致json_decode()
函數解析失敗。這里借着工作中遇到的一個問題整理一下相關的知識點,做個沉淀。
php中的單雙引號
區別
單引號中的內容會被認為就是純文本。雙引號中的內容則會經過解析,其中的變量、斜杠轉義符等會被處理為對應的值。
關於用法
在php7以前的版本中使用單引號處理速度比使用雙引號速度要快,但是php7以后兩者已經沒有區別。對於需要進行變量替換的字符串只能使用雙引號,對於純字符串鳥哥在他的PHP單引號和雙引號的區別文章中還是建議大家使用雙引號,理由是C/C++中雙引號表示字符串以及HTML中屬性值需要使用雙引號包裹,與別的語言習慣保持一致。
問題說明
解析一個前端通過post form表單提交過來的json字符串,但是一直報json_decode()
返回NULL,調用ljson_last_error()
返回4,調用json_last_error_msg()
返回Syntax error,但是json字符串能夠被在線的json解析器正確處理。
排查
前端輸入的字符串如下
[{"name":"測試添加車主","mobile":"13322232214"},{"name":"測試添加車主2","mobile":"13322232215"}]
將接收到的字符串使用var_dump()
打印出來
string '[{\"name\":\"測試添加車主\",\"mobile\":\"13322232214\"},{\"name\":\"測試添加車主2\",\"mobile\":\"13322232215\"}]' (length=124)
打印出的字符串是單引號包含並且內部包含了轉義字符串\"
將字符串復制出來,使用雙引號包裹在進行解析
<?php
$str = "[{\"name\":\"測試添加車主\",\"mobile\":\"13322232214\"},{\"name\":\"測試添加車主2\",\"mobile\":\"13322232215\"}]";
var_dump($str);
$array = json_decode($str, true);
var_dump($array);
var_dump(json_last_error());
var_dump(json_last_error_msg());
測試結果如下
PS D:\php\WWW> php .\test.php
string(108) "[{"name":"測試添加車主","mobile":"13322232214"},{"name":"測試添加車主2","mobile":"13322232215"}]"
array(2) {
[0]=>
array(2) {
["name"]=>
string(18) "測試添加車主"
["mobile"]=>
string(11) "13322232214"
}
[1]=>
array(2) {
["name"]=>
string(19) "測試添加車主2"
["mobile"]=>
string(11) "13322232215"
}
}
int(0)
string(8) "No error"
這里可以觀察到打印出來的json字符串被雙引號包裹,並且字符串內部的轉義字符\"
已經被處理為"
,json_decode()
函數也可以正確解析該json。因此這里可以確定問題就是接收到字符串內部含有轉義字符\"
但是外部不是使用雙引號包裹的。
解決
追了一下源代碼發現由於安全原因所有的輸入都經過addslashes()
函數處理防止sql注入,這里使用stripcslashes()
函數去掉json字符串中的反斜杠就解決了該問題。
總結php json_encode函數解析json字符串中的引號問題
- 內層的索引和值必須是雙引號
- 外層是單引號時,內層的雙引號不需要轉義(不能是
\"
,必須是"
) - 外層是雙引號時,內層的雙引號需要轉義(不能是
"
,必須是\"
)