PHP's micro-channel pay "Query corporate bank card payment API" or "query to the enterprise if the payment was credited" functional business processes

First, the brief scene

Before doing the micro-channel payment to the bank card business functions, but to the customer after the play money, the next day before arrival, for the timely feedback, so he made a "query to the enterprise if the payment was credited into account" function. This piece, I wrote a class directly, for processing, the following is the entire class code! 

Micro-channel document: https: //pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php chapter = 24_3?

Second, pay attention to the relevant

1, here involves some sensitive configuration in the configuration file, and, "to the enterprise query whether the payment credited into account" the need to use certificates, the need to prepare in advance, remember! 
2, partner_trade_no parameter is a string of characters in the play money to the bank card account is generated when the client, the results of data you can store your own, you can also return from a micro-channel in the end get. 
3, check whether the arrival, arrival situation is return_code, result_code, err_code whole is true, pay_succ_time not empty, it indicates arrival!

Third, the core code

<?php  defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * 查询给企业付款是否到账 - Service
 *
 * @desc 查看打款到银行卡的钱是否到账,如果,到账,更新distribute_log表 is_received 为 1
 * @author NangongYi
 * @time 2019/09/28 01:38:59
 *
 */

class Check_account_service extends FIT_Service
{

    /**
     * 字符池
     */
    const STING_POOL = '23456789ABCDEFGHJKLMNPQRSTUVWXYabcdefghijkmnpqrstuvwxy';

    /**
     * 字符长度
     */
    const STR_LENGTH = 18;

    /**
     * 构造方法 - 继承父类
     */
    public function __construct ()
    {
        parent::__construct();
    }

    /**
     * 微信 API - 配置参数
     */
    private function get_api_config_param()
    {
        $this->load->config('dict/dict_distribute.php');
        return $this->config->item('API_CONFIG');
    }

    /**
     * 查看订单分账是否到账
     * @param string $partner_trade_no : 分账时生成的唯一码
     * @return bool
     */
    private function check_order_distribute_is_received($partner_trade_no)
    {
        // 配置参数
        $api_config = $this->get_api_config_param();
        // 随机字符串
        $nonce_str = $this->product_random_str();
        // 准备数据
        $data = ['mch_id'=>$api_config['mch_id'], 'partner_trade_no'=>$partner_trade_no, 'nonce_str'=>$nonce_str];
        // 签名
        $sign = $this->product_sign_str($data);
        // xml数据整合
        $xmlData = $this->xml($data, $sign);
        // 数据请求
        $result = $this->curl_post_we_chat($api_config['query_bank'], $xmlData, true);
        // 结果处理
        if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' && $result['err_code'] == 'SUCCESS'){
            $success = ['is_received'=>1, 'received_time'=>$result['pay_succ_time']]; // 成功,返回到账时间,状态为 1
            return !empty($result['pay_succ_time']) ? $success : false;
        }else{
            $error = ['is_received'=>-1, 'rec_error_reason'=>$result['reason']]; // 失败,返回失败原因,状态为 -1,异常
            return $error;
        }
    }

    /**
     * xml数据 - 整合
     * @param array $data : 微信配置参数
     * @param string $sign : 生成签名
     * @return string
     */
    private function xml($data, $sign)
    {
        $xmlData="<xml>
    <mch_id>".$data['mch_id']."</mch_id>
    <nonce_str>".$data['nonce_str']."</nonce_str>
    <partner_trade_no>".$data['partner_trade_no']."</partner_trade_no>
    <sign>".$sign."</sign>
    </xml>";
        return $xmlData;
    }

    /**
     * 遍历所有的分账日志表中未付款记录,并进行标记
     * @desc 判断,如果到账,更新 distribute_log 表 is_received = 1
     */
    public function process_no_received_orders()
    {
        $this->load->dao("order_dao");
        $no_received_orders = $this->order_dao->get_no_received_orders();
        if(!$no_received_orders){
            return [];
        }
        $no_received_orders = $this->process_partner_trade_no($no_received_orders);
        $w_orderids = array_column($no_received_orders, null, 'partner_trade_no');
        $flag = 1;
        foreach ($w_orderids as $key=>$val) {
            // 过滤掉微信订单id为空的数据
            if(empty($val['partner_trade_no'])) continue;
            // 查看分账是否到账
            $res = $this->check_order_distribute_is_received($key);
            if(!$res) continue;
            // 如果到账,更改分账订单的状态为已分账 1
            $up_log = $this->order_dao->update_distribute_log_received($val['orderid'], $res);
            if(!$up_log) $flag --;
        }
        return $flag;
    }

    /**
     * 处理返回数据,返回 partner_trade_no
     * @param array $data : 订单数据
     * @return array
     */
    private function process_partner_trade_no($data)
    {
        foreach ($data as $key=>$val) {
            $data[$key]['partner_trade_no'] = $this->get_partner_trade_no($val['plg_log_info']);
        }
        return $data;
    }

    /**
     * 从json对象字符串中,返回 partner_trade_no
     * @param string $string : json对象
     * @return string
     */
    private function get_partner_trade_no($string)
    {
        $result = json_decode(substr($string,strrpos($string, '=')+1),true);
        return $result['partner_trade_no'];
    }

    /**
     * cURL方式POST数据到微信
     * @param string $url : 请求地址
     * @param array $data : 发送数据
     * @return mixed
     */
    private function curl_post_we_chat($url, $data, $ssl = false)
    {
        $api_config = $this->get_api_config_param();
        $ch = curl_init ();
        curl_setopt ( $ch, CURLOPT_URL, $url );
        curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
        if($ssl) {
            curl_setopt ( $ch,CURLOPT_SSLCERT,$api_config['sslcert']);
            curl_setopt ( $ch,CURLOPT_SSLKEY,$api_config['sslkey']);
        }
        curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
        curl_setopt ( $ch, CURLOPT_AUTOREFERER, 1 );
        curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
        $result = curl_exec($ch);
        if (curl_errno($ch)) {
            return 'Errno: '.curl_error($ch);
        }
        curl_close($ch);
        return $this->xmlToArray($result);
    }

    /**
     * 生成签名
     * @param array $paramArray : 微信请求参数
     * @param bool $isencode
     * @return mixed
     */
    private function product_sign_str($paramArray, $isencode=false)
    {
        $api_config = $this->get_api_config_param();
        $paramStr = '';
        ksort($paramArray);
        $i = 0;
        foreach ($paramArray as $key => $value)
        {
            if ($key == 'Signature'){
                continue;
            }
            if ($i == 0){
                $paramStr .= '';
            }else{
                $paramStr .= '&';
            }
            $paramStr .= $key . '=' . ($isencode?urlencode($value):$value);
            ++$i;
        }
        $stringSignTemp=$paramStr."&key=".$api_config['key'];
        $sign=strtoupper(md5($stringSignTemp));
        return $sign;
    }

    /**
     * 生成的随机字符串(小于32位)
     * @return string $randStr : 返回32位的字符
     */
    private function product_random_str()
    {
        $string = self::STING_POOL;
        $length = self::STR_LENGTH;
        $randStr = '';
        for($i = 0; $i < $length; $i++){
            $randStr .= $string[mt_rand(0, strlen($string)-1)];
        }
        return $randStr;
    }

    /**
     * 将xml转换成数组
     * @params xml $xml : xml数据
     * return array $data : 返回数组
     */
    private function xmlToArray($xml)
    {
        libxml_disable_entity_loader(true);//禁止引用外部xml实体
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        return json_decode(json_encode($xmlstring),true);
    }
}

Fourth, written in the last

Beginning to see the document, I felt micro-channel document, written or not so do the will of man, so read it several times, have understood, the key point is that "signature generation," It should be noted that, in addition, by Curl function when transferring data, will use the certificate, the document mentioned here, but still in this place, tangled for a long time! In short, this involves the payment of micro-channel are more stringent, requires careful understanding of the process!
Published 59 original articles · won praise 2 · Views 5579

Guess you like

Origin blog.csdn.net/LDR1109/article/details/102592608