有關PHP使用jeson_decode()轉數組失敗,json_last_error() 報4

摘要: php通過接口獲取到json數據用json_decode($jsonStr,true)轉數組失敗 ,用json_last_error_msg()獲取到錯誤信息:Syntax error 首先判斷是不是json數據格式錯誤,可以在線json格式化http://json.cn/看看有無錯誤 如果沒有錯誤,那麼原因估計是,接口提供方那邊輸出了bom頭造成或者報文body裏有回車符/換行符造成的。有關bom頭的處理,大家可以自行百度。回車符/換行符的處理:$post = str_replace(array("\r\n", "\r", "\n"), "", $post);//$post是待轉爲數組的json字符串。

最近在接第三方支付公司的一個支付通道,其他過程比較順利。最後在接通道發送的交易通知的接口時發生了一些問題。期間爲解決辦法,網上也扒了很多帖子,但都沒有解決問題,故而記錄一下,以便爲遇到類似問題的小夥伴拋磚引玉。
關於交易通知的接口文檔,通道(第三方支付公司)寫的比較簡單,截圖如下:
# 歡迎使用Markdown編輯器
OK,幹就是了,代碼如下:

            $post = file_get_contents("php://input");//接受通道參數
            $this->logger->info('post=>'.$post);//打印日誌,記錄接受參數
            $postResult = json_decode($post,true);//轉數組
            //如果轉失敗就報錯
            if(empty($postResult)){
                return $this->notifyResponse("FAIL",'無效報文');
            }

之所以用file_get_contents(“php://input”)接收參數,是因爲我接收的是同事寫一半的代碼(他已奔向他的星辰大海),我用的tp5.0的框架,測試用tp的$request->param()是收不到通道的參數的,後來問了下通道,說是採用的Content-type: application/json 形式的報文,具體的各種接收方式,大家可以自行百度。OK,繼續調接口,日誌如下:

[2020-05-12 08:56:37] paynotify.INFO: post=>{"data":"TeqD8BXaWyzWJj3+bahWIffqG09r+RgEPiD74ck2CNsYxwMC9GtOnVChGN1i8ClRNlFBYlAq6o+w +wu4+cZe2dXHTVyad0mEEd8P5pknfy0Cf9hrPz"}  {"logKey":"5eb9f445bda1a"}
[2020-05-12 08:56:37] paynotify.INFO: 返回通道信息 {"retCode":"FAIL","retMessage":"無效報文"} {"logKey":"5eb9f445bda1a"}

能接收到通道的請求報文,但是就是轉數組失敗。先確認自己的代碼有沒有問題,

//$post = file_get_contents("php://input");//接受通道參數
//$this->logger->info('post=>'.$post);//打印日誌,記錄接受參數
$post = '{"data":"TeqD8BXaWyzWJj3+bahWIffqG09r+RgEPiD74ck2CNsYxwMC9GtOnVChGN1i8ClRNlFBYlAq6o+w +wu4+cZe2dXHTVyad0mEEd8P5pknfy0Cf9hrPz"}';
$postResult = json_decode($post,true);//轉數組
//如果轉失敗就報錯
if(empty($postResult)){
    return $this->notifyResponse("FAIL",'無效報文');
}           

發現是OK的,可以解密。這就怪了,明明報文可以轉成數組,爲什麼通道的請求過來時就不行呢?OK,可以用json_last_error()(返回int值)或者json_last_error_msg()(返回字符串)函數獲取報錯:

$postResult = json_decode($post,true);
$jsonError = json_last_error_msg();
$this->logger->info('json_error=>'.$jsonError);
if(empty($postResult)){
    return $this->notifyResponse("FAIL",'無效報文');
}

日誌:

[2020-05-12 09:55:40] paynotify.INFO: post=>{"data":"TeqD8BXaWyzWJj3+bahWIffqG09r+RgEPiD74ck2CNsYxwMC9GtOnVChGN1i8ClRNlFBYlAq6o+w +wu4+cZe2dXHTVyad0mEEd8P5pknfy0Cf9hrPz"}  {"logKey":"5eba021ce1fde"}
[2020-05-12 09:55:40] paynotify.INFO: json_error=>Syntax error  {"logKey":"5eba021ce1fde"}
[2020-05-12 09:55:40] paynotify.INFO: 返回通道信息 {"retCode":"FAIL","retMessage":"無效報文"} {"logKey":"5eba021ce1fde"}

那就查導致報4或者Syntax error的可能原因。網上查了很多相關這個報錯的處理辦法,都沒有解決我的問題。然後自己模擬以json報文的方式請求自己也OK,因爲通道用的是java,就把通道請求過來的加密報文給公司的java同事,讓他們以json方式請求我的接口,發現也沒問題。那問題就在通道那裏,聯繫通道,通道說是不是因爲報文的body裏有回車符和換行符導致?好那就去除回車符、換行符:

$post = file_get_contents("php://input");
$this->logger->info('post=>'.$post);
//$post = '{"data":"TeqD8BXaWyzWJj3+bahWIffqG09r+RgEPiD74ck2CNsYxwMC9GtOnVChGN1i8ClRNlFBYlAq6o+w +wu4+cZe2dXHTVyad0mEEd8P5pknfy0Cf9hrPz"}';
//$postArr = explode('"',$post);//這是中間想到的一個方法:報文的結構是固定的,可以用explode()函數把報文內容截出來~!~
//$this->logger->info('postArr',$postArr);
$post = str_replace(array("\r\n", "\r", "\n"), "", $post);
$postResult = json_decode($post,true);
$jsonError = json_last_error_msg();
$this->logger->info('json_error=>'.$jsonError);
if(empty($postResult)){
    return $this->notifyResponse("FAIL",'無效報文');
}else{
	$this->logger->info('postResult=>',$postResult);
}

日誌:

[2020-05-12 10:47:18] paynotify.INFO: post=>{"data":"TeqD8BXaWyzWJj3+bahWIffqG09r+RgEPiD74ck2CNsYxwMC9GtOnVChGN1i8ClRNlFBYlAq6o+w +wu4+cZe2dXHTVyad0mEEd8P5pknfy0Cf9hrPz"}  {"logKey":"5eba0e36322d5"}
[2020-05-12 10:47:18] paynotify.INFO: json_error=>No error  {"logKey":"5eba0e36322d5"}
[2020-05-12 10:47:18] paynotify.INFO: postResult=> {"data":"TeqD8BXaWyzWJj3+bahWIffqG09r+RgEPiD74ck2CNsYxwMC9GtOnVChGN1i8ClRNlFBYlAq6o+w +wu4+cZe2dXHTVyad0mEEd8P5pknfy0Cf9hrPz"} {"logKey":"5eba0e36322d5"}

至此,問題解決。其實想想一開始,有想過可能是報文中一些符號的問題,但是當時只是用trim()去一下報文兩邊的空格,發現不行,就沒再考慮回車符、換行符這邊,後面就走偏了(T_T),外加跟公司java同事的通信一直很正常,就有點太相信通道的接口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章