paymentapple.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. defined('IN_WEB') or die('Include Error!');
  3. /**
  4. * 苹果支付
  5. app store返回码说明:
  6. 状态码 描述
  7. 21000 App Store无法读取你提供的JSON数据
  8. 21002 收据数据不符合格式
  9. 21003 收据无法被验证
  10. 21004 你提供的共享密钥和账户的共享密钥不一致
  11. 21005 收据服务器当前不可用
  12. 21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中
  13. 21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证
  14. 21008 收据信息是产品环境中使用,但却被发送到测试环境中验证
  15. 注意:在这里的非零状态码只是针对自动更新型订阅服务,不能将这些状态码用在测试其他类型产品的返回值中。
  16. */
  17. class ModelPaymentapple
  18. {
  19. private $_urlBuy = "https://buy.itunes.apple.com/verifyReceipt";
  20. private $_urlSanbox = "https://sandbox.itunes.apple.com/verifyReceipt";
  21. private $isSandbox = 0;
  22. private $_tkey = '';//苹果支付id
  23. private $_orderId = '';//苹果订单ID, 当客户端传过来为空时候使用
  24. /**
  25. * 验证苹果支付
  26. * @param $param
  27. * @param string $identifyKey
  28. * @return bool
  29. * Created by: Owen
  30. * Created on: 2020/12/5 10:54
  31. * PS:
  32. * 21000 App Store不能读取你提供的JSON对象
  33. 21002 receipt-data域的数据有问题 =》 receipt 错误
  34. 21003 receipt无法通过验证 =》 需要传输密码
  35. 21004 提供的shared secret不匹配你账号中的shared secret =》 需要传输密码
  36. 21005 receipt服务器当前不可用
  37. 21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送
  38. 21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务 =》 沙盒凭证
  39. 21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务
  40. */
  41. public function validateApplePay($param,$identifyKey = 'transaction_id', $passVersion = 0){
  42. $receipt = $param['receipt'];
  43. $password = "b20b5d00f0d143f39c9f598503fa4dc9";
  44. $transactionId = oo::functions()->escape($param['transactionId']);
  45. $url = $this->isSandbox ? $this->_urlSanbox : $this->_urlBuy;
  46. $postData = json_encode(["receipt-data" => $receipt]);
  47. $postDataPassWord = json_encode(["receipt-data" => $receipt,"password" => $password]);
  48. $ret = oo::functions()->curl($url, $postData);
  49. if($ret['status'] == 21004 || $ret['status'] == 21003){
  50. $ret = oo::functions()->curl($url,$postDataPassWord);
  51. }
  52. //TODO苹果临时过审包处理
  53. $bundleIds = ['com.astak.crazyspin', 'com.gworld.crazyspinios'];
  54. if($ret['status'] === 0 && in_array($ret['receipt']['bundle_id'], $bundleIds)){
  55. $in_app_data = $ret['receipt']['in_app'];
  56. if($identifyKey == "original_transaction_id"){
  57. array_multisort(array_column($in_app_data,'expires_date_ms'),SORT_DESC,$in_app_data);
  58. }
  59. foreach ($in_app_data as $row){
  60. if($row[$identifyKey] == $transactionId){
  61. return $row;
  62. }
  63. }
  64. oo::logs()->debug3(array("error"=>"transactionId error",'param'=>$param,'appleOrderInfo'=>$ret, "identifyKey" => $identifyKey), 'validateApplePay.log');
  65. return false;
  66. }else if($ret['status'] == 21007){//沙盒测试
  67. $retSandbox = oo::functions()->curl($this->_urlSanbox,$postData);
  68. if($retSandbox['status'] == 21004 || $retSandbox['status'] == 21003){
  69. $retSandbox = oo::functions()->curl($this->_urlSanbox,$postDataPassWord);
  70. }
  71. if($retSandbox['status'] === 0 && in_array($retSandbox['receipt']['bundle_id'], $bundleIds)){
  72. $in_app_data = $retSandbox['receipt']['in_app'];
  73. if($identifyKey == "original_transaction_id"){
  74. $in_app_data = array_reverse($in_app_data);
  75. }
  76. foreach ($in_app_data as $row){
  77. if($row[$identifyKey] == $transactionId){
  78. return $row;
  79. }
  80. }
  81. oo::logs()->debug3(array("error"=>"transactionId error",'param'=>$param,'appleOrderInfo'=>$retSandbox, "identifyKey" => $identifyKey), 'validateApplePay2.log');
  82. return false;
  83. }else{
  84. oo::logs()->debug3(array("error"=>"package name error",'param'=>$param,'appleOrderInfo'=>$retSandbox, "identifyKey" => $identifyKey), 'validateApplePay2.log');
  85. return false;
  86. }
  87. }else{
  88. oo::logs()->debug3(array("error"=>"status error","ret" => $ret, "receipt" => $receipt, "param" => $param, "identifyKey" => $identifyKey), 'validateApplePay2.log');
  89. return false;
  90. }
  91. }
  92. public function crazyGodDeliveryApplePay($param){
  93. $ret = $this->validateApplePay($param);//验证失败
  94. if( !$ret ){
  95. return false;
  96. }
  97. //本地的商品和appleID验证
  98. $orderInfo = $this->verificationCrazyGod($param['uid'],$param['orderId'],$ret);
  99. if (!$orderInfo) {
  100. return false;
  101. }
  102. return array_merge($ret,$orderInfo);
  103. }
  104. public function verificationCrazyGod($uid,$orderId,$param){
  105. $tb = otable::summarylist();
  106. $transaction_id = $param['transaction_id'];
  107. $sql = "SELECT * FROM {$tb} WHERE sl_platform_serial_num='{$transaction_id}' AND sl_status > 1";
  108. $transaction = oo::commonOprDb('common')->getOne($sql,1);
  109. if(!empty($transaction)){
  110. oo::logs()->debug3(array('uid' => $uid, 'msg' => 'transaction_id is be used'),'verification_apple.log');
  111. return ['order_id'=>$transaction['order_id'],'gid'=>$transaction['gid'], 'transaction_id'=>$transaction_id ,'status'=>2];
  112. }
  113. $tb = otable::payment($uid);
  114. $orderInfo = oo::commonOprDb('payment')->getOne("SELECT * FROM {$tb} WHERE order_id='{$orderId}' LIMIT 1",1);
  115. if(empty($orderInfo)){
  116. oo::logs()->debug3(array('uid' => $uid, 'msg' => 'order empty'),'verification_apple_error.log');
  117. return false;
  118. }
  119. $gid = intval($orderInfo['gid']);
  120. $status = intval($orderInfo['status']);
  121. return ['order_id'=>$orderId,'gid'=>$gid, 'transaction_id'=>$transaction_id ,'status'=>$status];
  122. }
  123. //验证参数 transaction-id是否用过
  124. public function verification($param)
  125. {
  126. $uid = oo::functions()->uint($param['uid']);
  127. $orderId = oo::functions()->escape($param['orderId']);
  128. $receipt = oo::functions()->escape($param['receipt']);
  129. $receipt = base64_decode($receipt);
  130. $p = '#.*purchase\-info" =(.*?);#iU';
  131. $str = preg_match_all($p, $receipt, $m);
  132. if ($str == 0) {//无法匹配
  133. oo::logs()->debug3(array('ret' => 1, 'uid' => $uid),'verification_apple.log');
  134. return false;
  135. }
  136. $keyInfo = trim($m[1][0], " \" ");//需要的关键数据
  137. $keyInfo = base64_decode($keyInfo);
  138. $p2 = '#.*"(.*?)" = "(.*?)";#iU';
  139. $str2 = preg_match_all($p2, $keyInfo, $m2);
  140. if ($str2 == 0) {//无法匹配
  141. oo::logs()->debug3(array('ret' => 2, 'uid' => $uid),'verification_apple.log');
  142. return false;
  143. }
  144. $paramName = array_flip($m2[1]);
  145. //获取2个关键参数 transaction-id 和 product-id
  146. $transaction_idKey = $paramName['transaction-id'];
  147. $product_idKey = $paramName['product-id'];
  148. $transaction_idVal = $m2[2][$transaction_idKey];//苹果业务ID
  149. $product_idVal = $m2[2][$product_idKey];//商品ID
  150. if ($orderId) {
  151. //验证商品对不对
  152. $dbGoods = oo::commonOprModel('goods')->getGpidByOrderIdCrazyGod($orderId);
  153. if (!$dbGoods) {
  154. oo::logs()->debug3(array('ret' => 3, 'uid' => $uid, 'orderId' => $orderId, 'dbGoods' => $dbGoods),'verification_apple.log');
  155. return false;
  156. }
  157. if ($dbGoods != $product_idVal) {//商品名称错误
  158. oo::logs()->debug3(array('ret' => 4, 'uid' => $uid, 'orderId' => $orderId, 'dbGoods' => $dbGoods, 'product_idVal' => $product_idVal, 'm2' => $m2, 'paramName' => $paramName),'verification_apple.log');
  159. return false;
  160. }
  161. }else{
  162. //此次判断没有订单ID时
  163. // $orderId = oo::commonOprModel('goods')->getOrderByUidAndgpid($uid, $product_idVal);
  164. $orderId = oo::commonOprModel('goods')->getOrderByUidAndgpidCrazyGod($uid, $product_idVal);
  165. if (!$orderId) {
  166. oo::logs()->debug3(array('ret' => 6, 'uid' => $uid, 'product_idVal' => $product_idVal),'verification_apple.log');
  167. return false;
  168. }
  169. $this->_orderId = $orderId;
  170. }
  171. $tkey = 'APPLEPAYT:'.$transaction_idVal;
  172. $tVal = oo::commonOprRedis('common')->get($tkey);
  173. if ($tVal) {
  174. oo::logs()->debug3(array('ret' => 5, 'uid' => $uid, 'transaction_idVal' => $transaction_idVal, 'm2' => $m2),'verification_apple.log');
  175. return false;
  176. }
  177. $this->_tkey = $transaction_idVal;
  178. return true;
  179. }
  180. /**
  181. * 苹果下单接口
  182. */
  183. public function deliveryApplePay($param){
  184. $data = array('code' => 2);
  185. //本地的商品和appleID验证
  186. $retVerification = $this->verification($param);
  187. if (!$retVerification) {
  188. return $data;
  189. }
  190. $ret = $this->validateApplePay($param);//验证失败
  191. if( !$ret ){
  192. return $data;
  193. }
  194. $uid = oo::functions()->uint($param['uid']);
  195. $orderId = oo::functions()->escape($param['orderId']);
  196. $orderId = empty($orderId) ? $this->_orderId : $orderId;
  197. $pubDeliveryRet = oo::commonOprModel('payment')->pubDelivery($uid, $orderId, $this->_tkey);
  198. if( $pubDeliveryRet != true ){
  199. oo::logs()->debug3(array('pubDeliveryRet' => $pubDeliveryRet, 'uid' => $uid, 'orderid' => $orderId), 'verification_apple.log');
  200. return $data;
  201. }
  202. //验证通过记录apple支付ID
  203. oo::commonOprRedis('common')->setex('APPLEPAYT:'.$this->_tkey, 1);
  204. $data['code'] = 1;
  205. return $data;
  206. }
  207. }