notify.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <?php
  2. /**
  3. * 接收IOS通知(支付结果)
  4. * @version
  5. * 1.0.0 Created at 2017-12-30. by --gwang
  6. * @author gwang (mail@wanggangzero.cn)
  7. * @copyright ? 2017-12-30, SJZ LoyalSoft Corporation & gwang. All rights reserved.
  8. *
  9. */
  10. include_once __DIR__ . '/../../../main.php'; # 导入game utils
  11. include_once __DIR__ . '/../Mo/payResp.php'; # 导入通用返回值结构
  12. include_once __DIR__ . '/../Mo/payRequest.php'; # 导入通用返回值结构
  13. require_once __DIR__ . '/../Mo/OrderNotice.php';
  14. require_once __DIR__ . '/config.ios.php'; # 配置文件, Ps. 里面用到了object
  15. use loyalsoft\CLog;
  16. use loyalsoft\HttpUtil;
  17. use loyalsoft\pay\OrderNotice;
  18. use loyalsoft\JsonUtil;
  19. /**
  20. * 客户端参数
  21. */
  22. class iosNotify {
  23. public $receipt;
  24. public $product_id;
  25. public $uid;
  26. public $cpOrderId;
  27. public $sandbox;
  28. public $callbackInfo;
  29. public $sign;
  30. public $notify_url;
  31. public function __construct($arr) {
  32. $this->receipt = $arr[0];
  33. $this->product_id = $arr[1];
  34. $this->uid = $arr[2]; # 剥离一下前缀
  35. $this->cpOrderId = $arr[3];
  36. $this->sandbox = ($arr[4] == '否') ? false : true; # ☄,客户端竟然传的"是"和"否".
  37. $this->callbackInfo = $arr[5];
  38. $this->sign = $arr[6];
  39. $this->notify_url = $arr[7];
  40. }
  41. }
  42. /**
  43. * 到苹果后台进行支付凭证校验
  44. * @param str $receipt
  45. */
  46. function VerifyFromApple($receipt, $sandbox, &$appleResp) {
  47. $cfg = config_for_ios::Inst($sandbox);
  48. $url = $cfg->verifySession_url;
  49. $ret = HttpUtil::makeRequest($url, JsonUtil::encode(array('receipt-data' => $receipt)));
  50. if ($ret['result']) { # 发送成功
  51. $data = JsonUtil::decode($ret['msg']);
  52. $in_app = $data->receipt->in_app[0];
  53. $appleResp = array(
  54. 'status' => $data->status, // # 收据状态
  55. 'product_count' => $in_app->quantity, // # 收据->内购->数量
  56. 'product_id' => $in_app->product_id, // # 收据->内购->道具编号
  57. 'transaction_id' => $in_app->transaction_id, // # 收据->内购->交易编号
  58. 'purchase_date' => $in_app->purchase_date, // # 收据->内购->购买时间
  59. 'appid' => $data->receipt->app_item_id // # 收据->appId(sandbox下为0)
  60. );
  61. if ($appleResp['status'] == 0) { # 验证结果为 valid
  62. if ($appleResp['appid'] == $cfg->appid # Appid合法
  63. || ($sandbox && $appleResp['appid'] == 0)) { # 或者沙箱下面appid=0
  64. CLog::pay("[IOS.notify] Apple后台验证通过." . $ret['msg']);
  65. return true;
  66. } else {
  67. CLog::pay("[IOS.notify] 凭证的Appid不符!." . $ret['msg']);
  68. }
  69. } else {
  70. CLog::pay("[IOS.notify] Apple后台验证失败." . $ret['msg']);
  71. }
  72. } else { # 通讯失败
  73. CLog::pay("[IOS.notify] 与Apple后台通讯失败.");
  74. }
  75. return false;
  76. }
  77. try {
  78. HttpUtil::PostOnly();
  79. // exit();
  80. CLog::pay("[IOS.notify] 收到支付回调请求: " . HttpUtil::getQueryString());
  81. $params = explode('&=&', HttpUtil::getQueryString()); # 提取参数
  82. $notify = new iosNotify($params);
  83. $cfg = config_for_ios::Inst($notify->sandbox); # 配置信息
  84. CLog::pay($notify);
  85. $sign = md5($notify->cpOrderId . $cfg->appkey); # 计算签名md5(cpOrderId+appkey)
  86. CLog::pay("[IOS.notify] " . "[签名原文]:" . $notify->sign);
  87. CLog::pay("[IOS.notify] " . "[签名结果]:" . $sign);
  88. if ($sign != $notify->sign) { # 验证签名
  89. exit(payResp::err(2, "Invalied sign!")); # 退出
  90. }
  91. $appleResp = null; # 苹果的返回值
  92. if (!VerifyFromApple($notify->receipt, $notify->sandbox, $appleResp)) { # 到苹果后台验证支付凭证
  93. exit(payResp::err(2, "Verify from apple server failed!")); # 退出
  94. }
  95. $order = OrderNotice::reParse_IOSOrder($notify, $appleResp); # 将参数归一化到order
  96. // var_dump($order);
  97. if ($order != null) {
  98. if ($order->Check()) { # 订单校验
  99. if (!$order->CheckDuplicateSdkOrder()) { # 渠道订单编号校验,防重放(简单修改)攻击
  100. CLog::pay("[IOS.notify] [异常]:" . "重复的sdk_orderId!"); # 日志
  101. exit(payResp::err(2, 'failure'));
  102. } else if ($order->status == 1) { # 订单状态, 1代表支付成功
  103. $order->UpdateOrderStatus(); # 更新订单状态,->已付款
  104. CLog::pay("[IOS.notify] [发货] 订单: " # 日志
  105. . $order->cpOrderId . ", 金额: " . $order->amount);
  106. } else if ($order->status == 2) { # status为2(failed)的情况
  107. $order->UpdateOrderStatus(); # 直接更新订单状态,->支付失败
  108. CLog::pay("[IOS.notify] [不发货] 订单: " . $order->cpOrderId);
  109. } else {
  110. CLog::pay("[IOS.notify] [处理结果]: FAILURE (未知的支付状态)"); # 日志
  111. exit(payResp::err(1, '重试'));
  112. }
  113. CLog::pay("[IOS.notify] [处理结果]:" . "SUCCESS"); # 日志
  114. exit(payResp::ok('success'));
  115. }
  116. }
  117. CLog::pay("[IOS.notify] [处理结果]:" . "FAILURE"); # 日志
  118. exit(payResp::err(2, 'failure'));
  119. } catch (Exception $e) {
  120. CLog::pay("[IOS.notify] " . $e->getMessage()); # 日志
  121. exit(payResp::err(1, $e->getMessage())); # 未知异常, 告诉客户端可以重试
  122. }