PHP program debugging WeChat payment callback request parameter diary

Foreword: 

Before debugging, I also took a lot of detours. First, I learned how to use http_build_query

The function of the http_build_query function in PHP is to use a given array to generate a URL-encode query string.
 
Let’s first look at the basic syntax of the http_build_query function: 

string http_build_query ( mixed $query_data [, string $numeric_prefix [, string $arg_separator [, int $enc_type = PHP_QUERY_RFC1738 ]]] )

To put it simply, http_build_query() is to convert an array into the parameter string after the url question mark?, and automatically perform urlencode processing. 

http_build_query parameter description

parameter value
query_data Can be an array or an object containing properties.
A query_data array can be a simple one-dimensional structure, or it can be an array of arrays (which in turn can contain other arrays).
If query_data is an object, only public properties will be added to the result.
numeric_prefix If numeric subscripts are used in the underlying array and this parameter is given, the value of this parameter will be used as the prefix of the numeric subscript elements in the underlying array.
This is to allow PHP or other CGI programs to obtain valid variable names when decoding the data later.
arg_separator Unless specified and used, arguments are separated by arg_separator.output.
enc_type

By default PHP_QUERY_RFC1738 is used.

If enc_type is PHP_QUERY_RFC1738, the encoding will be encoded according to the » RFC 1738 standard and application/x-www-form-urlencoded media type, spaces will be encoded as plus signs (+).

If enc_type is PHP_QUERY_RFC3986, it will be encoded according to » RFC 3986, spaces will be percent-encoded (%20).

Example 1 of http_build_query
, using a one-dimensional associative array:

<?php
$vars = array('page' => 4, 'search' => 'this & that');
$qs = http_build_query($vars);
$url = 'http://www.example.com/search.php?' . $qs;
echo $url;
?>

Running result: http://www.example.com/search.php?page=4&search=this+%26+that


2. What if it is a mixed array of indexed arrays and associative arrays? It automatically adds a numeric index.

http_build_query also has a parameter that can prefix the numeric index, let's try again:

$data = array(
    'foo',
    'bar',
    'site'=>'www.yumingku.net',
    'name'=>'nowa magic');
echo http_build_query($data, "nm_");

/* output
nm_0=foo&nm_1=bar&site=www.yumingku.net&name=nowa+magic
*/

3. Use two-dimensional arrays

<?php
$vars = array("database"=>array("sql","mysql"),"dev"=>array('a'=>'php','b'=>'java'));
$qs = http_build_query($vars);
$url = 'http://www.example.com/search.php?' . $qs;
echo $url;
?>

Running result: http://www.example.com/search.php?database%5B0%5D=sql&database%5B1%5D=mysql&dev%5Ba%5D=php&dev%5Bb%5D=java

 

4. Use object

<?php
class myClass { 
   var $foo; 
   var $baz; 
   function myClass() { 
    $this->foo = 'bar'; 
    $this->baz = 'boom'; 
   } 
} 
$data = new myClass(); 
echo 'http://www.example.com/search.php?'.http_build_query($data); 

  The result of running is: http://www.example.com/search.php?foo=bar&baz=boom

Generate a url-encoded request string using the given associative (or subscripted) array. The parameter formdata can be an array or an object containing properties. A formdata array can be a simple one-dimensional structure, or it can be an array of arrays (which in turn can contain other arrays). If numeric subscripts are used in the base array and the numeric_prefix parameter is given, the value of this parameter will be used as the prefix of the numeric subscript elements in the base array. This is to allow PHP or other CGI programs to obtain valid variable names when decoding the data later.

Closer to home

The reason for writing this article is that something happened when debugging WeChat payment today. The callback was successful, but the logic could not be successfully executed. The prediction should be the problem of the parameter name. To solve this problem, you must first know that the callback request returns to the server. What parameters are carried!

There are many ways, here are one or two of them

First parse the data of the WeChat payment callback request

        $postStr = file_get_contents('php://input');
		//禁止引用外部xml实体
		libxml_disable_entity_loader(true);        
        $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
        if ($postObj === false) {
            exit;
            die('parse xml error');
        }
        if ($postObj->return_code != 'SUCCESS') {
            exit;
            die($postObj->return_msg);
        }
        if ($postObj->result_code != 'SUCCESS') {
            exit;
            die($postObj->err_code);
        }
        $arr = (array)$postObj;//参数数组

The above xml result reference returned by WeChat payment is written to a txt file through the file_put_content function for easy viewing and analysis

The difference between the use of file_put_content and fopen, fwrite, fclose combination is as follows

Write or append a string to a file, file_put_content is the most suitable choice for writing a string to a file or appending a string content at one time, and returns the number of bytes written
data data type: string, array (not for multidimensional arrays), stream Resource
description:
1. If the file does not exist, create it.
2. If the file exists and already has content, the file content will be cleared by default. Set FILE_APPEND in the parameter to avoid clearing.
       For example: file_put_contents("test.txt", "This is another something." , FILE_APPEND); Append a string to the end

Note:
1. The file_put_contents file must be an absolute path, not relative, and the http protocol does not work (cannot be written remotely)
2. file_get_contents can be read remotely using the http protocol
3. General conditions The following file_put_contents can replace the combination of fopen, fwrite, and fclose, but they are not completely equivalent, especially when writing large data, the difference is more obvious. When inputting large data (exceeding the current allocated memory), you should Use a combination of three such as fwrite to write, because the fwrite function is written and read at the same time, and file_put_contents is written at one time, so at this time, memory overflow will occur when file_put_contents is written, resulting in weird problems. When the input data is small, the execution speed of file_put_contents is faster.
    Summary: a. Large files, high concurrency use fwrite to write
               b. Small data use file_put_contents

Example:


$file = 'log.txt';
 
$site =  $postObj;//回调通知参数 
// 向文件追加写入内容
// 使用 FILE_APPEND 标记,可以在文件末尾追加内容
// LOCK_EX 标记可以防止多人同时写入
file_put_contents($file, $site, FILE_APPEND | LOCK_EX);


执行成功后,打开 log.txt 文件,内容为:

<xml><appid><![CDATA[appid]]></appid>
<bank_type><![CDATA[OTHERS]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[N]]></is_subscribe>
<mch_id><![CDATA[1596799561]]></mch_id>
<nonce_str><![CDATA[if380wsc1pxekh9juxyk29yoqlzrzvdf]]></nonce_str>
<openid><![CDATA[oRCfRwZdSsUhbXrMtIaQ9CNfOjMM]]></openid>
<out_trade_no><![CDATA[202006102028252]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[FC607BEAD46E4FE2E4CB0B812E9836A0]]></sign>
<time_end><![CDATA[20200610202834]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id><![CDATA[4200000547202006103632209909]]></transaction_id>
</xml>



支付结果通知官方文档
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8

After seeing the detailed information of the callback notification parameters, the rest knows what to do. The debugging methods of other payment interfaces are basically similar! It is still necessary to look at the official return type and the request type are slightly different

Also attach the usage examples of fopen, fwrite, fclose

<?php
$myfile = fopen("newfile.txt", "w") or die("Unable to open file!");
$txt = "Bill Gates\n";
fwrite($myfile, $txt);
$txt = "Steve Jobs\n";
fwrite($myfile, $txt);
fclose($myfile);
?>

C函数fopen中可对打开的文件设置多种读写模式,需要说明下fwrite的追加模式是怎么回事,网上很多文章都说的不清不楚,只说a是追加,w不能追加,其实很多误解,这里需要澄清:


w:表示fopen文件时会清空掉原文件(如果存在)的信息,并重新写入,在不fclose文件的情况下,多次fwrite也是追加写入到文件末尾的,不会覆盖之前fwrite的内容。
a:表示fopen文件时会保留原文件(如果存在)的信息,并追加到末尾写入,每次fwrite写入到文件末尾。

其他说明:
w:  文本写入,只写
w+:可读可写
wb:  二进制写入,只写
wb+:  二进制写入或读出,可读可写
a:对fopen的文件追加写入,文本形式
ab:对fopen的文件追加写入,二进制形式
ab+:对fopen的文件追加写入或读出,二进制形式
————————————————
//获取域名或主机地址
echo $_SERVER['HTTP_HOST']."<br />"; #mp.csdn.net

//获取网页地址
echo $_SERVER['PHP_SELF']."<br />"; #/p/1.html

//获取网址参数
echo $_SERVER["QUERY_STRING"]."<br />"; #id=1

//获取用户代理
echo $_SERVER['HTTP_REFERER']."<br />";

//获取完整的url
echo 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
echo 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'];
#http://mp.csdn.net/p/1.html?id=1

//包含端口号的完整url
echo 'http://'.$_SERVER['SERVER_NAME'].':'.$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
#http://mp.csdn.net:80/p/1.html?id=1

//只取路径
$url='http://'.$_SERVER['SERVER_NAME'].$_SERVER["REQUEST_URI"];
echo dirname($url);
#http://mp.csdn.net/p

 

Guess you like

Origin blog.csdn.net/Sncdma/article/details/106686164