适用范围:多数继承 app\api\controller\Api 的接口。
flowchart TD
A["客户端提交密文 body"] --> B["Api::_initialize"]
B --> C["读取 header/body device"]
C --> D["AES-128-ECB 解密 body"]
D --> E{"qmapidebug 或解密失败?"}
E -->|debug 明文| F["input() 参数"]
E -->|正常密文| G["JSON decode"]
F --> H["校验 appid"]
G --> H
H --> I["查询 App: id/appkey/client_appkey/gameid"]
I --> J["MD5 签名校验"]
J --> K["补默认 channel_id"]
K --> L["checkLogin"]
L --> M["业务 handler"]
M --> N["jsonResult"]
N --> O{"debug?"}
O -->|是| P["明文 JSON"]
O -->|否| Q["AES 加密 JSON"]
关键兼容点:
qmapidebug 是 header bool 值,开启后不需要密文。jsonResult 会把业务 code 映射为 code=1/0,原始错误码保留在 err_code。代码入口:Api::checkLogin
白名单逻辑:
register、sendSms、CheckUpdate、complexLogin、startup、forget、privacy、config、Third。$noNeedLogin 定义。校验步骤:
imeil 必填。token。token => imeil,必须存在且与当前 imeil 一致。auth_code(token, DECODE, auth_key) 解出:
useridusernamegameidsub_usernametoken_randomtypetoken|{type}|{userid}|{gameid},必须等于 token_random。useridgameidusernametokensub_usernamemember_channel_id = getChannelId(userid, gameid)v2.user/personalIdentity 进行请求频率限制。Go 迁移建议:
AuthUser,不要继续改写请求参数 map。auth_code 算法需要先移植并做 golden test,否则旧 token 全部失效。主要代码:v1\Login.php
入口:Login::index
核心步骤:
IpLimit 限制国内 IP。level=3。auth_code(password, ENCODE, auth_key) 后匹配 cy_members。loginProcess。职责:
offline_time。cy_member_channel_game_rel。nw_subaccount。cy_logininfo。Token 生成格式:
userid|username|gameid|sub_username|token_random|sdk
返回字段通常包含:
tokenusernamesub_usernameuseridgameidimeiloffline_time入口:
Login::loginQqLogin::third第三方登录会按不同类型查找或创建用户:
wx_uidqq_uiddy_uid如果第三方用户不存在,会生成随机账号、写入主账号和相关扩展表,然后复用 loginProcess。
主要代码:v1\Register.php
入口:Register::index
核心步骤:
usernamepasswordgameidimeilchannel_iddy_channel_idtypelevel=3。imeil 查询是否已有游客账号,有则直接返回登录信息。mobile。cy_memberscy_member_historycy_memberstwomw_dy_channel_relloginProcess:
cy_member_channel_game_relnw_subaccountGo 迁移注意:
RegisterUser 和 CreateSession。regidterHandle,迁移时注意不要遗漏。channel_id=EMPTY_CHANNEL_ID 有特殊开关。主入口:v1\Pay::index
实际核心服务:application\service\GamePayService::gamePay
flowchart TD
A["客户端 Pay::index"] --> B["Pay.add 参数校验"]
B --> C["GamePayService::gamePay"]
C --> D["支付方式场景识别"]
D --> E["PayHandle 随机/管控选择真实 paytype"]
E --> F["校验用户、子账号、渠道、游戏、CP 回调地址"]
F --> G["代金券/专属币/平台币金额计算"]
G --> H["重复下单和 attach 去重"]
H --> I["防沉迷充值限额"]
I --> J["事务写 cy_pay 与 cy_paycpinfo"]
J --> K["扣减券/专属币/平台币"]
K --> L{"real_amount 是否为 0?"}
L -->|是| M["订单直接支付成功"]
L -->|否| N["PayService 生成第三方支付参数"]
M --> O["返回订单结果"]
N --> O
来自 validate\Pay.php:
gameiduseridappidserveridservernameamountroleidattachchannel_idproductnamepaytypeimeilmc_idcoupon_member_id| 字段/标识 | 含义 |
|---|---|
amount |
游戏充值原始金额 |
real_amount |
需要第三方支付的现金金额 |
ptb_amt |
游戏专属币使用金额 |
coin_amt |
平台币使用金额 |
coupon_member_id |
代金券实例 ID |
coupon_amount |
本单抵扣的代金券金额 |
mix-xxx |
专属币加第三方混合支付 |
coin-xxx |
平台币加第三方混合支付 |
coupon |
纯代金券支付 |
主要表:
cy_paycy_paycpinfocy_member_historycy_member_channel_game_relnw_subaccountmember_coin/member_zscoin 相关明细表cy_coupon_memberGamePayService 创建 CP 发货通知参数时,签名大致包含:
orderid={orderid}&username={sub_username}&gameid={gameid}&roleid={roleid}&serverid={serverid}&paytype={paytype}&amount={amount}&paytime={time}&attach={attach}&appkey={appkey}
签名方式:MD5。
Go 迁移注意:
attach 在同一 gameid 下必须唯一。paytype 处理。bc* 高精度函数,Go 中必须用 decimal,不能用 float64。主要入口:
v1\PayNotify.php:游戏充值现金回调。v1\PayNotifyCoin.php:平台币充值现金回调。service\PayNotifyService.php:平台币订单成功后加余额。service\NotifyService.php:聚合渠道支付回调。常见方法:
alipayalipayAopwxpayh5ybzf_payldzf_wx_payqzl_payyyyb_payxty_payairwallexdianhun统一核心:PayNotify::updateOrder
流程:
cy_pay。cy_pay.status=1、pay_time、必要的回调流水号。cy_paycpinfo.payflag=1。PayCallback::callBackToCp(orderid)。Go 迁移注意:
success、SUCCESS、ok、XML、JSON。updateOrder 必须幂等。核心:PayNotifyService::updateOrderCoin
流程:
member_coin_pay。member_coin_pay.status=1member_coin_info 余额流水。cy_members.amount。入口:v2\Coin::pay
核心服务:application\service\MemberCoinService::payCoin
流程:
member_coin_pay 订单,订单号前缀为 COIN。PayService 生成支付参数。PayNotifyCoin 或 PayNotifyService。入口:v2\Order.php
能力:
orderList:游戏充值和平台币充值列表。orderInfo:订单详情,含 CP 发货状态。cancelOrder:取消待支付订单。getMemberCoinList:平台币流水。getPayInfo:支付相关信息。状态:
| status | 含义 |
|---|---|
0 |
待支付 |
1 |
支付成功 |
2 |
已取消 |
3 |
超时取消 |
Go 迁移注意:
cy_pay。member_coin_pay。主要代码:v1\ComplexLogin.php、complex\*.php
流程:
nw_complex_channel 和 cy_polychannel_game。app\api\complex\{Channel}。checkLogin 校验渠道登录签名。nw_complex_members。主要代码:
v1\ComplexPay.phpv1\ComplexPayNotify.phpservice\NotifyService.phpcomplex\*.php支付回调流程:
flowchart TD
A["渠道支付回调"] --> B["NotifyService::notify(channel,input)"]
B --> C["查询 complex_channel"]
C --> D["查询 polychannel_game"]
D --> E["实例化 complex adapter"]
E --> F["paySign 或 paySignH5"]
F --> G["getData 归一化 orderid/amount/sub_orderid"]
G --> H["checkOrder 校验 nw_complex_pay 金额"]
H --> I["事务更新 nw_complex_pay 和 cy_paycpinfo"]
I --> J["更新 nw_complex_members.total_pay_amount"]
J --> K["PayCallback::callBackToCp"]
K --> L["adapter getSuccess/getFail"]
Go 迁移注意:
getData 的归一化字段至少应统一为 order_id、amount、provider_order_id。paySignH5 分支,不能只实现标准 paySign。主要代码:
v1\Identity.phpv2\User::personalIdentityv2\ComplexAuthentication.phpapplication\service\CommonService::authentication实名类型:
cy_memberstwo。game_auth_type 和 game_bizid 调用外部 authSdk.Authentication,结果写 nw_subaccount。防沉迷逻辑:
Go 迁移注意:
isMeetAgeByIDCard 结果一致。auth_status 语义。CommonService::handleBelongToBinding 会按实名信息调整渠道归属,是支付分成相关逻辑,不能遗漏。主要代码:v2\Coupon.php
能力:
getMyCoupon:用户券列表,按未使用、已使用、已失效分组。getCoupon:可领取券列表。receiveCoupon:领取券。exchangeCoupon:兑换码换券。getPayCoupon:获取当前订单金额可用券。领取流程:
cy_coupon。cy_coupon_member 中未绑定用户的券码。receive_num。member_id。支付使用:
GamePayService 调用 CouponMember::getPayCoupon。is_use=1 改为 2。is_use=1 改为 3。主要代码:controller\mlbb
独立登录态:
user_id|username|token_random|sdk|mlbb。token|sdk|mlbb|user_id。Mlbb::validateToken。核心活动:
Login::index:活动登录,创建 lr_user_info。Game::reservation:预约。Game::getRole:查询 SDK 角色。Game::bandRole:绑定角色到活动账户。Game::getTask / getTaskComplete:任务读取和完成。Game::handleLottery:抽奖,消耗次数,发礼包码或代金券。Activity::getInfo:冒险团信息。Activity::claim:阶段奖励领取。Other::importGift:导入礼包码。主要表:
lr_user_infolr_user_gatheringlr_user_tasklr_user_winninglr_prizelr_prize_giftlr_claimGo 迁移建议: