<?php
/**
 * 支付宝支付通知类
 * Created by PhpStorm.
 * User: phperstar
 * Date: 2019/11/28
 * Time: 5:00 PM
 */
namespace JinDouYun\Controller\Common;

use Mall\Framework\Core\StatusCode;

use JinDouYun\Controller\BaseController;
use JinDouYun\Model\Order\MOrder;
use JinDouYun\Model\Market\MVipCard;

class AliPayNotify extends BaseController
{
    //使用文件读取文件格式，请只传递该值(支付宝公钥文件方式)
    private $alipayPublicKey = null;

    //使用读取字符串格式，请只传递该值(支付宝公钥字符串方式)
    private $alipayrsaPublicKey;

    public function __construct($isCheckAcl = false, $isMustLogin = false, $checkToken = false)
    {
        parent::__construct($isCheckAcl, $isMustLogin, $checkToken);

        $this->alipayrsaPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnb7lP7zW4CR94yAgljj4yNc4j7NyWd7oGhCB5/0PBcg9QQ91bj4dAUMFyu/QNJK2ez2jqVUoDeB13ueOVxwBfINwLm4k6Kw5PnDkSJBuGyE9bUQDEPOpm3/UZmza86uvm5xce54gyn+9OqH0Z4iWt4CuVAG4IwwAaVVhNLwxJQAiKWHYtNzWHtvNQV81CFEJinnV8u1sh40ex0FZlnjcyvSwzOILVqEsLYUaXpp0XDnk9j1yC+sVSAjezIQUplptWuGBnMiA2Q5nZtryNm+BaaVV0wNCs5wTUr4hfvxcw4UitkNEwJTVKp2JUYMgNV8JuX+y/MEIASN8nMiL+rDzYwIDAQAB';

    }

    /**
     * 支付宝回调处理方法
     * 官网文档地址:https://docs.open.alipay.com/204/105301/
     * @throws \Exception
     */
    public function notify()
    {
        $flag = $this->rsaCheckV1($_POST, NULL, "RSA2");
        //验签
        if($flag){
            //处理业务，并从$_POST中提取需要的参数内容
            if($_POST['trade_status'] == 'TRADE_SUCCESS' || $_POST['trade_status'] == 'TRADE_FINISHED'){ // 处理交易完成或者支付成功的通知
                file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'回调数据'.var_export($_POST,true).PHP_EOL,FILE_APPEND);
                $passback_params = urldecode($_POST['passback_params']); // 回传参数
                $attach = explode('|',$passback_params);

                if(empty($attach)){
                    exit('fail');
                }

                $enterpriseId = $attach[0];
                unset($attach[0]);
                $userCentId = $attach[1];
                unset($attach[1]);

                $allOrdersId = array_values($attach);

                if (strpos( $_POST['out_trade_no'],'tmp') === false || substr($_POST['out_trade_no'],0,3) == 'tmp') {
                    $updateOrderData = [
                        'outerTradeNo' => $_POST['trade_no'], // 该交易在支付宝系统中的交易流水号
                        'payType' => StatusCode::$payType['aliPay'],
                        'payStatus' => StatusCode::$standard,
                        'orderStatus' => StatusCode::$orderStatus['waitDelivery'],
                        'payTime' => strtotime($_POST['gmt_payment']), // 支付完成时间
                        'total_fee'=> $_POST['total_amount'],//支付金额
                        'pay_way'=>StatusCode::$payType['aliPay']
                    ];

                    $objMOrder = new MOrder($userCentId, $enterpriseId);
                    if(strpos( $_POST['out_trade_no'],'tmp') === false){
                        $result = $objMOrder->updateOrderPayData($updateOrderData, ['id'=>$allOrdersId,'no'=>$_POST['out_trade_no']],true);

                    }else{
                        $result = $objMOrder->updateOrderPayData($updateOrderData, ['id'=>$allOrdersId,'outerTradeNo'=>$_POST['out_trade_no']],true);
                    }

                    if(!$result->isSuccess()){
                        file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'修改订单状态失败'.var_export($result->getData(),true).PHP_EOL,FILE_APPEND);
                        exit('fail');
                    }else{
                        exit('success');// 响应success表示业务处理成功，告知支付宝无需在异步通知
                    }
                }

                //处理会员卡订单
                if (strpos( $_POST['out_trade_no'],'tmp') !== false && substr($_POST['out_trade_no'],0,3) == 'vip') {
                    $vipOrderData = [
                        'outerTradeNo' => $_POST['trade_no'],
                        'payType' => StatusCode::$payType['aliPay'],
                        'payStatus' => StatusCode::$standard,
                        'payTime' => strtotime($_POST['gmt_payment']), // 支付完成时间
                    ];

                    $objMVipCard = new MVipCard($enterpriseId, $userCentId);

                    $result = $objMVipCard->updateVipOrderPayData($vipOrderData, ['id'=>$allOrdersId,'outerTradeNo'=>$_POST['out_trade_no']],true);


                    if(!$result->isSuccess()){
                        file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'修改会员卡订单状态失败'.var_export($result->getData(),true).PHP_EOL,FILE_APPEND);
                        exit('fail');
                    }else{
                        exit('success');// 响应success表示业务处理成功，告知支付宝无需在异步通知
                    }
                }

                exit('fail');

            }else{
                file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'状态错误'.var_export($_POST,true).PHP_EOL,FILE_APPEND);
            }
        }else{
            file_put_contents('/www/wwwroot/logs/apiqnys.liuniukj.com/alipay.log',date('Y-m-d H:i:s').'签名验证失败'.var_export($_POST,true).PHP_EOL,FILE_APPEND);
        }
    }


    /** rsaCheckV1 & rsaCheckV2
     *  验证签名
     *  在使用本方法前，必须初始化AopClient且传入公钥参数。
     *  公钥是否是读取字符串还是读取文件，是根据初始化传入的值判断的。
     **/
    public function rsaCheckV1($params, $rsaPublicKeyFilePath,$signType='RSA') {
        $sign = $params['sign'];
        $params['sign_type'] = null;
        $params['sign'] = null;
        return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath,$signType);
    }

    public function getSignContent($params) {
        ksort($params);

        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {

                // 转换成目标字符集
                $v = $this->characet($v, "UTF-8");

                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }

        unset ($k, $v);
        return $stringToBeSigned;
    }

    /**
     * 校验$value是否非空
     *  if not set ,return true;
     *    if is null , return true;
     **/
    protected function checkEmpty($value)
    {
        if (!isset($value))
            return true;
        if ($value === null)
            return true;
        if (trim($value) === "")
            return true;

        return false;
    }

    /**
     * 转换字符集编码
     * @param $data
     * @param $targetCharset
     * @return string
     */
    function characet($data, $targetCharset)
    {
        if (!empty($data)) {
            $fileType = "UTF-8";
            if (strcasecmp($fileType, $targetCharset) != 0) {
                $data = mb_convert_encoding($data, $targetCharset, $fileType);
                //				$data = iconv($fileType, $targetCharset.'//IGNORE', $data);
            }
        }

        return $data;
    }

    function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA')
    {

        if($this->checkEmpty($this->alipayPublicKey)){

            $pubKey= $this->alipayrsaPublicKey;
            $res = "-----BEGIN PUBLIC KEY-----\n" .
                wordwrap($pubKey, 64, "\n", true) .
                "\n-----END PUBLIC KEY-----";
        }else {
            //读取公钥文件
            $pubKey = file_get_contents($rsaPublicKeyFilePath);
            //转换为openssl格式密钥
            $res = openssl_get_publickey($pubKey);
        }

        ($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');

        //调用openssl内置方法验签，返回bool值

        if ("RSA2" == $signType) {
            $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
        } else {
            $result = (bool)openssl_verify($data, base64_decode($sign), $res);
        }

        if(!$this->checkEmpty($this->alipayPublicKey)) {
            //释放资源
            openssl_free_key($res);
        }

        return $result;
    }
}