payRequest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. <?php
  2. /**
  3. * 统一的预创建订单请求对象
  4. * @version
  5. * 1.0.0 Created at 2017-12-21. by --gwang
  6. * @author gwang (mail@wanggangzero.cn)
  7. * @copyright ? 2017-12-21, SJZ LoyalSoft Corporation & gwang. All rights reserved.
  8. */
  9. class PayRequest extends loyalsoft\Object_ext {
  10. const orderTab = 'tab_order_tab';
  11. /**
  12. * @var bool 是否测试(金额降低100倍)(线上版千万别瞎改)
  13. */
  14. const isTest = true;
  15. /**
  16. * @var string 充值回调透传参数(len=250)
  17. */
  18. public $callbackInfo;
  19. /**
  20. * 各平台取自己的配置信息
  21. * @var string 充值回调地址(len=100)
  22. */
  23. public $notifyUrl;
  24. /**
  25. * @var string 订单ID (len=30)
  26. */
  27. public $cpOrderId;
  28. /**
  29. * @var float 充值金额 (单位:元) (特:入库时会x100转为分)
  30. */
  31. public $amount;
  32. /**
  33. * @var string 货币类型(默认:CNY)
  34. */
  35. public $currency = 'CNY';
  36. /**
  37. * @var string 平台UID
  38. */
  39. public $accountId;
  40. /**
  41. * @var int 游戏中的分区id
  42. */
  43. public $zoneid;
  44. /**
  45. * @var string 渠道
  46. */
  47. public $channel;
  48. /**
  49. * @var string 道具id
  50. */
  51. public $product_id;
  52. /**
  53. * @var string 道具名称
  54. */
  55. public $product_name;
  56. /**
  57. *
  58. * @var string 道具描述
  59. */
  60. public $product_desc;
  61. /**
  62. * @var string 道具单价
  63. */
  64. public $product_price;
  65. /**
  66. * @var int (购买)道具数量
  67. */
  68. public $product_count;
  69. /**
  70. * @var 防沉迷年龄段 ( -1 未实名, 0(0~7) 8(8~16) 16(16~18) 18(18+成年)
  71. * #[optional]
  72. */
  73. public $ageRange = -1;
  74. /**
  75. * @var string 公会id
  76. */
  77. public $party_id;
  78. public $party_name;
  79. /**
  80. * @var string 签名算法, 目前固定为MD5
  81. */
  82. public $signType = "MD5";
  83. /**
  84. *
  85. * @var string MD5(签名内容+apiKey)
  86. */
  87. public $sign;
  88. /**
  89. * @var int 订单编号
  90. */
  91. private $order_id;
  92. /**
  93. *
  94. * @return array 订单写入数据库
  95. */
  96. public function InserDataBase() {
  97. // return false; # 2019.10.9 关闭充值
  98. if (self::isTest) {
  99. $this->channel = 'tester'; # 测试
  100. }
  101. $arr = get_object_vars($this); # 转为数组
  102. $arr["uid"] = $arr["accountId"]; # 转换下变量名称
  103. $arr["amount"] = $arr["amount"] * 100; # 拉起平台时传的单位是元,比如UC还有易接,而游戏后台存储的是分
  104. unset($arr["signType"]); # 毙掉后台不需要的数据
  105. unset($arr["sign"]);
  106. unset($arr["accountId"]);
  107. unset($arr['order_id']);
  108. unset($arr['ageRange']);
  109. unset($arr['product_desc']);
  110. $n = loyalsoft\daoInst()->update(self::orderTab)
  111. ->data($arr)
  112. ->where('id')->eq($this->order_id)
  113. ->exec();
  114. return $n == 1;
  115. }
  116. /**
  117. * @return array 拉取签名参数数组
  118. */
  119. public function uc_GetData2Sign() {
  120. $sid = array('callbackInfo', 'amount', 'notifyUrl', 'cpOrderId', 'accountId');
  121. $arr = array();
  122. foreach (get_object_vars($this) as $key => $value) {
  123. if (in_array($key, $sid)) {
  124. $arr[$key] = $value;
  125. }
  126. }
  127. return $arr;
  128. }
  129. /**
  130. * @return array 普通返回值数组
  131. */
  132. public function retData() {
  133. $sid = array('callbackInfo', 'amount', 'product_price', 'product_count', 'notifyUrl', 'cpOrderId');
  134. $arr = array();
  135. foreach (get_object_vars($this) as $key => $value) {
  136. if (in_array($key, $sid)) {
  137. $arr[$key] = $value;
  138. }
  139. }
  140. return $arr;
  141. }
  142. /**
  143. * @return array 小七手游订单结构(未签名)
  144. * @deprecated since version 0 已废弃
  145. */
  146. public function x7sy_retData() {
  147. $ret = array(
  148. 'extends_info_data' => $this->callbackInfo, // // 透传参数
  149. 'game_area' => $this->zoneid,
  150. 'game_guid' => $this->accountId,
  151. 'game_level' => 0,
  152. 'game_orderid' => $this->cpOrderId,
  153. 'game_price' => $this->product_price, // // 对方要求单位:元
  154. 'game_role_id' => "no",
  155. 'game_role_name' => "no",
  156. 'notify_id' => "3788", // // 如果只有一个可以设置为-1,但不可以设置为0
  157. 'subject' => $this->product_name
  158. );
  159. return $ret;
  160. }
  161. /**
  162. * @return array 易接返回值数组
  163. * @deprecated since version 0 已废弃
  164. */
  165. public function yijie_retData() {
  166. return $this->retData();
  167. }
  168. /**
  169. * 华为 订单通知魔改版
  170. * @param type $params 参考:https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References/server-data-model-0000001050986133#section264617465219
  171. */
  172. static function From_HW($params) {
  173. $infoArr = array();
  174. \loyalsoft\CLog::pay($params);
  175. $callbackInfo = $params['developerPayload'];
  176. $infos = explode(',', $callbackInfo); # uid,zoneid,cpOrderId,productId
  177. $infoArr['orderId'] = $params['orderId'];
  178. $infoArr['accountId'] = $infos[0]; # uid
  179. $infoArr['amount'] = number_format($params['price'] / 100, 2, '.', ''); # 分转元 # 华为给过来是分, 这里先转换为元, 入库时再统一以分为单位
  180. $infoArr['currency'] = $params['currency']; # 如果是海外会有不同的货币类型
  181. $infoArr['product_id'] = $params['productId'];
  182. $infoArr['product_count'] = 1;
  183. $infoArr['channel'] = "huawei"; # 华为
  184. $infoArr['zoneid'] = (int) $infos[1]; # 分区信息
  185. $infoArr['callbackInfo'] = $callbackInfo;
  186. $o = new payRequest($infoArr);
  187. $o->cpOrderId = $infos[2]; # 重新修订下cpOrderId
  188. return $o;
  189. }
  190. public function __construct($arg = null) {
  191. parent::__construct($arg);
  192. if (!$this->accountId || !$this->product_id || !$this->amount || !$this->channel) {
  193. \loyalsoft\CLog::pay('参数缺失');
  194. exit('{"err":1,"msg":"参数缺失!"}');
  195. }
  196. $this->callbackInfo = $this->accountId . "," . $this->zoneid;
  197. if (self::isTest) {
  198. $this->amount *= 0.01; // 也可以改成固定值 0.01, 更省钱些.
  199. }
  200. // if ($this->channel == "mi") {
  201. // $this->amount = 1;
  202. // }
  203. if ($this->amount) {
  204. // $this->amount = number_format($this->amount, 2, '.', '');
  205. // if ('soft' == $this->channel) { # 2018年1月15号以前固定为1分钱测试
  206. // $this->amount = number_format(0.01, 2, '.', '');
  207. // $this->product_price = 0.01;
  208. // } else //
  209. if ($this->amount != loyalsoft\GameConfig::shop_getItem($this->product_id)->price) {
  210. // var_dump($this->product_id);
  211. // var_dump(loyalsoft\GameConfig::shop_getItem($this->product_id)->price);
  212. \loyalsoft\CLog::pay('金额不符' . $this->amount . " ");
  213. exit('{"err":1,"msg":"金额不符!"}');
  214. }
  215. }
  216. loyalsoft\daoInst()->insert(self::orderTab) # 创建一个新的订单
  217. ->data(array('order_ts' => loyalsoft\now()))
  218. ->exec();
  219. $this->order_id = loyalsoft\daoInst()->select('last_insert_id() as id')->fetch('id'); # 取刚才创建的订单的自增id
  220. $this->cpOrderId = LoyalsoftAPPID . \date('ymdHi') . substr(sprintf("%1$06d", $this->order_id), -6); # 商户唯一id(尾部附加自增id后6位数)
  221. $this->callbackInfo .= "," . $this->cpOrderId; # 将cpOrderId追加到透传参数中
  222. $this->notifyUrl = $this::get_notify_url(); # 自动提取支付回调地址
  223. }
  224. /**
  225. * PS. 仅限pay.php作为入口使用才行
  226. * @return string 获取支付回调地址,
  227. */
  228. public function get_notify_url() {
  229. $url = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER["REQUEST_URI"];
  230. switch ($this->getPlatStr()) {
  231. case "hykb":
  232. $nurl = substr($url, 0, strpos($url, "pay.php")) . "notify_hykb.php";
  233. break;
  234. default:
  235. $nurl = substr($url, 0, strpos($url, "pay.php")) . "notify.php";
  236. break;
  237. }
  238. return $nurl; # 回调地址
  239. }
  240. /**
  241. * 未成年检查 (国内版)
  242. * @return type
  243. */
  244. public function AntiAdditionCheck() {
  245. $uid = $this->accountId;
  246. $ageRange = $this->ageRange;
  247. $ageRange = 18;
  248. $amt = $this->amount;
  249. if (isset($uid) && isset($ageRange)) {
  250. $monthTS = loyalsoft\TimeUtil::tsMonthBegin(); # 本月初起始时间戳
  251. $dayTS = loyalsoft\TimeUtil::tsDayBegin(); # 当天起始时间戳
  252. $monthTotal = loyalsoft\daoInst()
  253. ->select("sum(`amount`)/100 as total") # 总金额(单位:分转元)
  254. ->from(self::orderTab)
  255. ->where("uid")->eq($uid) # 该玩家
  256. ->andWhere("status")->eq(1) # 成交订单
  257. ->andWhere("order_ts")->ge($monthTS) # 本月
  258. ->fetch('total');
  259. if (!is_numeric($monthTotal)) {
  260. $monthTotal = 0;
  261. }
  262. $dayTotal = loyalsoft\daoInst()
  263. ->select("sum(`amount`)/100 as total") # 总金额(单位:分转元)
  264. ->from(self::orderTab)
  265. ->where("uid")->eq($uid) # 该玩家
  266. ->andWhere("status")->eq(1) # 成交订单
  267. ->andWhere("order_ts")->ge($dayTS) # 今日
  268. ->fetch('total');
  269. if (!is_numeric($dayTotal)) {
  270. $dayTotal = 0;
  271. }
  272. if ($ageRange < 0 || !is_numeric($ageRange)) {
  273. return \payResp::err(1, "未完成实名认证的用户暂不提供充值.");
  274. } else if ($ageRange < 8) {
  275. return \payResp::err(1, "未满8周岁的用户暂不提供充值.");
  276. } else if ($ageRange < 16) { # 单笔/每月: 50,200
  277. if ($amt > 50) {
  278. return \payResp::err(1, "单笔充值金额不高于50¥");
  279. }
  280. // if (($amt + $dayTotal) > 100) {
  281. // return \Resp::err(1, "单日累计充值金额不高于100¥");
  282. // }
  283. if (($amt + $monthTotal) > 200) {
  284. return \payResp::err(1, "当月累计充值金额不高于200¥");
  285. }
  286. } else if ($ageRange < 18) { # 单笔/每月: 100,400
  287. if ($amt > 100) {
  288. return \payResp::err(1, "单笔充值金额不高于100¥");
  289. }
  290. // if (($amt + $dayTotal) > 100) {
  291. // return \Resp::err(1, "单日累计充值金额不高于100¥");
  292. // }
  293. if (($amt + $monthTotal) > 400) {
  294. return \payResp::err(1, "当月累计充值金额不高于400¥");
  295. }
  296. }
  297. return \payResp::ok("ok");
  298. }
  299. return \payResp::err(-1, "参数不足"); # 其他情况
  300. }
  301. /**
  302. * 获得用户的平台字符串
  303. * @return string
  304. */
  305. function getPlatStr() {
  306. if (strrpos($this->accountId, '_') > 0) {
  307. return substr($this->accountId, strrpos($this->accountId, '_') + 1); # 提取平台字符串
  308. } else {
  309. return "";
  310. }
  311. //PS. substr() 函数返回字符串的一部分 strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。
  312. }
  313. /**
  314. * 获得用户的平台唯一id.
  315. * @return string
  316. */
  317. public function getPlatOid() {
  318. return substr($this->accountId, 0, strrpos($this->accountId, '_')); # 提取平台字符串
  319. //PS. substr() 函数返回字符串的一部分 strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。
  320. }
  321. }