<?php
defined('IN_WEB') or die('Include Error!');
/**
 * 苹果支付

app store返回码说明：
状态码 描述
21000 App Store无法读取你提供的JSON数据
21002 收据数据不符合格式
21003 收据无法被验证
21004 你提供的共享密钥和账户的共享密钥不一致
21005 收据服务器当前不可用
21006 收据是有效的，但订阅服务已经过期。当收到这个信息时，解码后的收据信息也包含在返回内容中
21007 收据信息是测试用（sandbox），但却被发送到产品环境中验证
21008 收据信息是产品环境中使用，但却被发送到测试环境中验证
注意：在这里的非零状态码只是针对自动更新型订阅服务，不能将这些状态码用在测试其他类型产品的返回值中。

 */
class ModelPaymentapple
{

    private $_urlBuy = "https://buy.itunes.apple.com/verifyReceipt";
    private $_urlSanbox = "https://sandbox.itunes.apple.com/verifyReceipt";
    private $isSandbox = 0;
    private $_tkey = '';//苹果支付id
    private $_orderId = '';//苹果订单ID, 当客户端传过来为空时候使用

    /**
     * 验证苹果支付
     * @param $param
     * @param string $identifyKey
     * @return bool
     * Created by: Owen
     * Created on: 2020/12/5 10:54
     *  PS:
     *  21000	App Store不能读取你提供的JSON对象
        21002	receipt-data域的数据有问题                                     =》  receipt 错误
        21003	receipt无法通过验证                                           =》  需要传输密码
        21004	提供的shared secret不匹配你账号中的shared secret               =》  需要传输密码
        21005	receipt服务器当前不可用
        21006	receipt合法，但是订阅已过期。服务器接收到这个状态码时，receipt数据仍然会解码并一起发送
        21007	receipt是Sandbox receipt，但却发送至生产系统的验证服务          =》  沙盒凭证
        21008	receipt是生产receipt，但却发送至Sandbox环境的验证服务
     */
    public function validateApplePay($param,$identifyKey = 'transaction_id', $passVersion = 0){
        $receipt = $param['receipt'];
        $password = "b20b5d00f0d143f39c9f598503fa4dc9";
        $transactionId = oo::functions()->escape($param['transactionId']);
        $url = $this->isSandbox ? $this->_urlSanbox : $this->_urlBuy;
        $postData         = json_encode(["receipt-data" => $receipt]);
        $postDataPassWord = json_encode(["receipt-data" => $receipt,"password" => $password]);
        $ret = oo::functions()->curl($url, $postData);
        if($ret['status'] == 21004 || $ret['status'] == 21003){
            $ret = oo::functions()->curl($url,$postDataPassWord);
        }
        //TODO苹果临时过审包处理
        $bundleIds = ['com.astak.crazyspin', 'com.gworld.crazyspinios'];
        if($ret['status'] === 0 && in_array($ret['receipt']['bundle_id'], $bundleIds)){
            $in_app_data = $ret['receipt']['in_app'];
            if($identifyKey == "original_transaction_id"){
                array_multisort(array_column($in_app_data,'expires_date_ms'),SORT_DESC,$in_app_data);
            }
            foreach ($in_app_data as $row){
                if($row[$identifyKey] == $transactionId){
                    return $row;
                }
            }
            oo::logs()->debug3(array("error"=>"transactionId error",'param'=>$param,'appleOrderInfo'=>$ret, "identifyKey" => $identifyKey), 'validateApplePay.log');
            return false;
        }else if($ret['status'] == 21007){//沙盒测试
            $retSandbox = oo::functions()->curl($this->_urlSanbox,$postData);
            if($retSandbox['status'] == 21004 || $retSandbox['status'] == 21003){
                $retSandbox  = oo::functions()->curl($this->_urlSanbox,$postDataPassWord);
            }
            if($retSandbox['status'] === 0 && in_array($retSandbox['receipt']['bundle_id'], $bundleIds)){
                $in_app_data = $retSandbox['receipt']['in_app'];
                if($identifyKey == "original_transaction_id"){
                    $in_app_data = array_reverse($in_app_data);
                }
                foreach ($in_app_data as $row){
                    if($row[$identifyKey] == $transactionId){
                        return $row;
                    }
                }
                oo::logs()->debug3(array("error"=>"transactionId error",'param'=>$param,'appleOrderInfo'=>$retSandbox, "identifyKey" => $identifyKey), 'validateApplePay2.log');
                return false;
            }else{
                oo::logs()->debug3(array("error"=>"package name error",'param'=>$param,'appleOrderInfo'=>$retSandbox, "identifyKey" => $identifyKey), 'validateApplePay2.log');
                return false;
            }
        }else{
            oo::logs()->debug3(array("error"=>"status error","ret" => $ret, "receipt" => $receipt, "param" => $param, "identifyKey" => $identifyKey), 'validateApplePay2.log');
            return false;
        }
    }

    public function crazyGodDeliveryApplePay($param){
        $ret = $this->validateApplePay($param);//验证失败
        if( !$ret ){
            return false;
        }

        //本地的商品和appleID验证
        $orderInfo = $this->verificationCrazyGod($param['uid'],$param['orderId'],$ret);
        if (!$orderInfo) {
            return false;
        }

        return array_merge($ret,$orderInfo);
    }

    public function verificationCrazyGod($uid,$orderId,$param){
        $tb = otable::summarylist();
        $transaction_id = $param['transaction_id'];
        $sql = "SELECT * FROM {$tb} WHERE sl_platform_serial_num='{$transaction_id}' AND sl_status > 1";
        $transaction = oo::commonOprDb('common')->getOne($sql,1);
        if(!empty($transaction)){
            oo::logs()->debug3(array('uid' => $uid, 'msg' => 'transaction_id is be used'),'verification_apple.log');
            return ['order_id'=>$transaction['order_id'],'gid'=>$transaction['gid'], 'transaction_id'=>$transaction_id ,'status'=>2];
        }

        $tb = otable::payment($uid);
        $orderInfo = oo::commonOprDb('payment')->getOne("SELECT * FROM {$tb} WHERE order_id='{$orderId}' LIMIT 1",1);
        if(empty($orderInfo)){
            oo::logs()->debug3(array('uid' => $uid, 'msg' => 'order empty'),'verification_apple_error.log');
            return false;
        }
        $gid    = intval($orderInfo['gid']);
        $status = intval($orderInfo['status']);

        return ['order_id'=>$orderId,'gid'=>$gid, 'transaction_id'=>$transaction_id ,'status'=>$status];
    }


    //验证参数 transaction-id是否用过
    public function verification($param)
    {
        $uid = oo::functions()->uint($param['uid']);
        $orderId = oo::functions()->escape($param['orderId']);
        $receipt = oo::functions()->escape($param['receipt']);
        $receipt = base64_decode($receipt);
        $p = '#.*purchase\-info" =(.*?);#iU';
        $str = preg_match_all($p, $receipt, $m);
        if ($str == 0) {//无法匹配
            oo::logs()->debug3(array('ret' => 1, 'uid' => $uid),'verification_apple.log');
            return false;
        }
        $keyInfo = trim($m[1][0], " \" ");//需要的关键数据
        $keyInfo = base64_decode($keyInfo);
        $p2 =  '#.*"(.*?)" = "(.*?)";#iU';
        $str2 = preg_match_all($p2, $keyInfo, $m2);
        if ($str2 == 0) {//无法匹配
            oo::logs()->debug3(array('ret' => 2, 'uid' => $uid),'verification_apple.log');
            return false;
        }
        $paramName = array_flip($m2[1]);
        //获取2个关键参数 transaction-id 和 product-id
        $transaction_idKey = $paramName['transaction-id'];
        $product_idKey = $paramName['product-id'];

        $transaction_idVal = $m2[2][$transaction_idKey];//苹果业务ID
        $product_idVal = $m2[2][$product_idKey];//商品ID

        if ($orderId) {
            //验证商品对不对
            $dbGoods = oo::commonOprModel('goods')->getGpidByOrderIdCrazyGod($orderId);
            if (!$dbGoods) {
                oo::logs()->debug3(array('ret' => 3, 'uid' => $uid, 'orderId' => $orderId, 'dbGoods' => $dbGoods),'verification_apple.log');
                return false;
            }

            if ($dbGoods != $product_idVal) {//商品名称错误
                oo::logs()->debug3(array('ret' => 4, 'uid' => $uid, 'orderId' => $orderId, 'dbGoods' => $dbGoods, 'product_idVal' => $product_idVal, 'm2' => $m2, 'paramName' => $paramName),'verification_apple.log');
                return false;
            }
        }else{
            //此次判断没有订单ID时
//            $orderId = oo::commonOprModel('goods')->getOrderByUidAndgpid($uid, $product_idVal);
            $orderId = oo::commonOprModel('goods')->getOrderByUidAndgpidCrazyGod($uid, $product_idVal);
            if (!$orderId) {
                oo::logs()->debug3(array('ret' => 6, 'uid' => $uid, 'product_idVal' => $product_idVal),'verification_apple.log');
                return false;
            }
            $this->_orderId = $orderId;
        }

        $tkey = 'APPLEPAYT:'.$transaction_idVal;
        $tVal = oo::commonOprRedis('common')->get($tkey);
        if ($tVal) {
            oo::logs()->debug3(array('ret' => 5, 'uid' => $uid, 'transaction_idVal' => $transaction_idVal, 'm2' => $m2),'verification_apple.log');
            return false;
        }

        $this->_tkey = $transaction_idVal;
        return true;
    }

    /**
     *	苹果下单接口
     */
    public function deliveryApplePay($param){
        $data = array('code' => 2);

        //本地的商品和appleID验证
        $retVerification = $this->verification($param);
        if (!$retVerification) {
            return $data;
        }

        $ret = $this->validateApplePay($param);//验证失败
        if( !$ret ){
            return $data;
        }

        $uid = oo::functions()->uint($param['uid']);
        $orderId = oo::functions()->escape($param['orderId']);
        $orderId = empty($orderId) ? $this->_orderId : $orderId;

        $pubDeliveryRet = oo::commonOprModel('payment')->pubDelivery($uid, $orderId, $this->_tkey);
        if( $pubDeliveryRet != true ){
            oo::logs()->debug3(array('pubDeliveryRet' => $pubDeliveryRet, 'uid' => $uid, 'orderid' => $orderId), 'verification_apple.log');
            return $data;
        }

        //验证通过记录apple支付ID
        oo::commonOprRedis('common')->setex('APPLEPAYT:'.$this->_tkey, 1);

        $data['code'] = 1;
        return $data;
    }
}
