微信支付V3

admin8个月前Laravel431

 public static function pay($order_sn = '11111', $money = '12', $uid = 7)

    {

        

        

        $num=Db::table('order')->where(array('order_no'=>$order_sn))->first(); 

        if(!$num){

            return $this->error('网络异常,请重新下单');

        }

         

        $openid = Db::table('member')->where(array('id' => $uid))->value('openid');

        // $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/app';

        $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi';

        $data = [

            'appid' => self::$wxconfig['app_id'],

            'mchid' => self::$wxconfig['mch_id'],

            'description' => "订单支付",

            'out_trade_no' => $order_sn,

            'notify_url' => request()->getSchemeAndHttpHost() . '/api/pay/notify',

            'time_expire' => date("Y-m-d\TH:i:sP", (time() + 300)),

            'amount' => [

                'total' => $money * 100,

                'currency' => 'CNY',

            ],

            'payer' => [

                'openid' => $openid,

            ],

        ];


        $prepay_id = self::curl($url, json_encode($data), 'POST');

        if (isset($prepay_id['code'])) {

            return self::pay_error('error', $prepay_id['message']);

        }

        $msg = [

            'appId' => self::$wxconfig['app_id'], // 这是appid

            'timeStamp' => (string)time(), // 这是时间戳

            'nonceStr' => self::createNonceStr(), // 这是随机码

            'package' => 'prepay_id=' . $prepay_id['prepay_id'], // 这是预支付id

            'signType' => 'RSA',

        ];

        $sign = self::sign_SHA256_with_RSA($msg);

        $msg['sign'] = $sign;

        return $msg;

    }



 public function notify()

    {

        $wxData = file_get_contents("php://input");

        file_put_contents('log1111.txt', $wxData);


        $getCallBackArray = json_decode($wxData, true);

//        //获取需要解密字段

        $associatedData = $getCallBackArray['resource']['associated_data'];

        $nonceStr = $getCallBackArray['resource']['nonce'];

        $ciphertext = $getCallBackArray['resource']['ciphertext'];


        $ciphertexts = $this->decryptToString($associatedData, $nonceStr, $ciphertext);

        $resultArray = json_decode($ciphertexts, true);


        if ($resultArray['trade_state'] === 'SUCCESS') {

            $out_trade_no = $resultArray['out_trade_no'];


            $info = DB::table('order')->where(array('order_no' => $out_trade_no, 'status' => '0'))->first();


            if ($info) {

                $data['status'] = 1;

                $data['pay_time'] = time();

                // 预定订单

                if ($info->is_reserve == '1') {

                    $data['pay_succ'] = 2;

                } else {

                    $data['pay_succ'] = 1;

                }



                Db::beginTransaction();

                $msg = Db::table('order')->where(array('order_no' => $out_trade_no))->update($data);

                // 处理库存

                $good = Db::table('order_good')->where(array('order_id' => $info->id))->get();


                foreach ($good as $k => $v) {

                    if ($v->sku) {

                        self::good_num($v->good_id, $v->sku, $v->num);

                    } else {

                        Db::table('good')->where(array('id' => $v->good_id))->update(['good_num' => DB::raw('good_num - ' . $v->num), 'sold' => DB::raw('sold + ' . $v->num)]);

                    }

                }


                if ($msg !== false) {

                    Db::commit();

                    if ($data['pay_succ'] == '1') {

                        $this->reward($info->user_id, $info->order_no, $info->dist_one_money, $info->dist_two_money);

                    }

                    exit('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>');

                } else {

                    Db::rollBack();

                    return false;

                }

            } else {

                return false;

            }

        }

    }


    public static function sign_SHA256_with_RSA($data)

    {

        if (!in_array('sha256WithRSAEncryption', \openssl_get_md_methods(true))) {

            throw new \RuntimeException("当前PHP环境不支持SHA256withRSA");

        }

        $appId = $data['appId'];

        $prepayId = $data['package'];

        $nonce = $data['nonceStr']; // 随机数

        $timestamp = $data['timeStamp']; // 时间戳

        $message =

            $appId . "\n" .

            $timestamp . "\n" .

            $nonce . "\n" .

            $prepayId . "\n";



        $merchantPrivateKeyFilePath = self::getPrivateKey(base_path() . '/public/cert/apiclient_key.pem');

        openssl_sign($message, $raw_sign, $merchantPrivateKeyFilePath, 'sha256WithRSAEncryption');

        $sign = base64_encode($raw_sign);

        return $sign;

    }


    public static function getPrivateKey($filepath)

    {

        return openssl_get_privatekey(file_get_contents($filepath));

    }


    public static function createNonceStr($length = 16)

    {

        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

        $str = '';

        for ($i = 0; $i < $length; $i++) {

            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);

        }

        return $str;

    }



    public static function curl($url, $json_str, $method)

    {

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);

        if ($json_str) {

            curl_setopt($ch, CURLOPT_POSTFIELDS, $json_str);

        }

        $token = self::getAuthorization($url, $json_str, $method);

        $header = [

            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token,

            'Accept: application/json',

            'Content-Type: application/json; charset=utf-8',

            'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',

        ];

        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        curl_setopt($ch, CURLOPT_VERBOSE, 1);

        curl_setopt($ch, CURLOPT_HEADER, 1);

        $response = curl_exec($ch);

        $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);

        return json_decode(substr($response, $header_size), true);

    }



    public static function getAuthorization($url, $body, $method)

    {

        $url_parts = parse_url($url);

        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));

        $timestamp = time();

        $nonce_str = md5(time());

        $message = $method . "\n" .

            $canonical_url . "\n" .

            $timestamp . "\n" .

            $nonce_str . "\n" .

            $body . "\n";

        $mch_private_key = file_get_contents(base_path() . '/public/cert/apiclient_key.pem');


        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');

        $sign = base64_encode($raw_sign);

        return sprintf(

            'mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',

            self::$wxconfig['mch_id'],

            $nonce_str,

            $timestamp,

            self::$wxconfig['serial_no'],

            $sign

        );

    }



    public function decryptToString($associatedData, $nonceStr, $ciphertext)

    {

        if (strlen(self::$wxconfig['key']) != 32) {

            return false;

        }

        $ciphertext = \base64_decode($ciphertext);

        if (strlen($ciphertext) <= 16) {

            return false;

        }

        // ext-sodium (default installed on >= PHP 7.2)

        if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') &&

            \sodium_crypto_aead_aes256gcm_is_available()) {

            return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, self::$wxconfig['key']);

        }

        // ext-libsodium (need install libsodium-php 1.x via pecl)

        if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&

            \Sodium\crypto_aead_aes256gcm_is_available()) {

            return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, self::$wxconfig['key']);

        }

        // openssl (PHP >= 7.1 support AEAD)

        if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {

            $ctext = substr($ciphertext, 0, -16);

            $authTag = substr($ciphertext, -16);

            return \openssl_decrypt($ctext, 'aes-256-gcm', self::$wxconfig['key'], \OPENSSL_RAW_DATA, $nonceStr,

                $authTag, $associatedData);

        }

        throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');

    }


相关文章

解密微信绑定的手机号

public function mobile() { $code = request()->input('code'); if (!$code) { return $this-&...

按照距离远近排序

   $distance = "ACOS(SIN(( $lat * 3.1415) / 180 ) *SIN((lat * 3.1415) / 180 ) +COS((...

查找下级所有数据

public function bottom($mid = 3){    $members = DB::select('select id,parent_id,`level...

base64 处理图片

public function images(){    $image = request()->input('image');    i...

不重复 的推荐码

public function getcode(){    do {        $code = rand(10000000, 99999...

上传图片

public function image(){    $obFile = request()->file('image');    if...