PreProc.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <?php
  2. namespace loyalsoft;
  3. /**
  4. * Description of PreProc
  5. * 预处理流程
  6. * 提供数据包预处理机制、加解密、合法化判定等等
  7. * @author jgao
  8. */
  9. class PreProc {
  10. /**
  11. * tk判定
  12. * @param Req $req
  13. * @return int 返回操作结果,0:成功,其余为错误码
  14. */
  15. public static function tk($req) {
  16. my_Assert(!config::Inst()->isBaned($req->uid), ErrCode::err_server_updating); # 检查封号
  17. # 检查是否处于更新阶段,暂停对玩家请求的响应。
  18. if (GAME_ONLINE # 外网
  19. && self::isUpdating() # 更新
  20. && !config::Inst()->isTester($req->uid)) { # 排除测试号
  21. return ErrCode::err_server_updating;
  22. }
  23. $ssd = GameConfig::service_schedule_getItem(1); # 服务计划(固定只有1条)
  24. if (now() > $ssd->startts && now() < $ssd->endts) { # 在维护期间
  25. // return ErrCode::err_server_maintaining;
  26. Err(ErrCode::err_server_maintaining, $ssd->reason);
  27. }
  28. // if (!GAME_ONLINE || config::Inst()->isTester($req->uid)) { # 内网不做token校验操作
  29. return ErrCode::ok;
  30. // }
  31. if ($req->cmd == CmdCode::cmd_user_getzonelist) { # 如果是获取分区列表的消息初始化tk信息,不做校验
  32. $siginfo = SigInfo::InitSig($req); # 初始化sigInfo
  33. $req->sig = $siginfo->sig; # 每次resp会从req上取sig值返回
  34. $req->msgid = PreProc::createMsgId($siginfo); # 初始化msgid
  35. $siginfo->msgid = SigInfo::calcMsgid($siginfo, $req); # sigInfo和本次的$req身上的msgid,用于下次消息校验,
  36. self::updateUserSigInfo($req, $siginfo); # 写入Cmem,下次登录的时候校验
  37. return ErrCode::ok;
  38. }
  39. # 其余消息,全部进行校验
  40. $siginfo = self::getUserSigInfo($req); # 1.从Cmem读取证书验证信息
  41. if ($siginfo == null) {
  42. return ErrCode::err_signo;
  43. }
  44. if ($req->sig != $siginfo->sig) { # 2.如果一次性证书不一致,则证明已经在其他地方登录
  45. return ErrCode::err_anotherlogin;
  46. }
  47. if ($siginfo->msgid != SigInfo::calcMsgid($siginfo, $req)) { # 3.如果消息id错位,则证明该条消息非法
  48. return ErrCode::err_illegal;
  49. }
  50. if (now() - $req->ts > OFFSET_MSGTIME) { # 4.如果服务端客户端时间戳超过规定误差,则消息非法
  51. return ErrCode::err_outtime;
  52. }
  53. # 更新siginfo
  54. $siginfo->msgnum++; # 消息编号递增
  55. $req->msgid = PreProc::createMsgId($siginfo); # ...
  56. $siginfo->msgid = SigInfo::calcMsgid($siginfo, $req); # 计算新的
  57. self::updateUserSigInfo($req, $siginfo); # 回写siginfo
  58. return ErrCode::ok; # 返回操作结果,0:成功,其余为错误码
  59. }
  60. public static function createMsgId($siginfo) {
  61. $temp = 8888 - $siginfo->msgnum;
  62. return substr(md5(substr($siginfo->uid, 2, 20) . $temp . substr($siginfo->sig, 5, 15)), 7, 23);
  63. }
  64. /**
  65. * 返回是否处于更新中
  66. * @return boolean
  67. */
  68. public static function isUpdating() {
  69. $ts = now();
  70. if ($ts > glc()->updatingBeginTs && $ts < glc()->updatingEndTs) {
  71. return true;
  72. }
  73. return false;
  74. }
  75. /**
  76. * 把玩家的SigInfo写入数据库
  77. * @param Req $req
  78. * @param SigInfo $siginfo
  79. */
  80. public static function updateUserSigInfo($req, $siginfo) {
  81. gMem()->set(MemKey_User::Sig($req->zoneid, $siginfo->uid), $siginfo);
  82. }
  83. /**
  84. * 从Cmem中读取玩家的SigInfo数据
  85. * @param Req $req
  86. * @return SigInfo
  87. */
  88. public static function getUserSigInfo($req) {
  89. return gMem()->get(MemKey_User::Sig($req->zoneid, $req->uid));
  90. }
  91. }
  92. /**
  93. * 校验信息
  94. */
  95. class SigInfo {
  96. public $uid;
  97. public $zoneid;
  98. public $sig;
  99. public $msgnum;
  100. public $msgid;
  101. /**
  102. *
  103. * @param SigInfo $siginfo
  104. * @param Req $req
  105. */
  106. public static function calcMsgid($siginfo, $req) {
  107. return substr(md5($siginfo->sig . $req->msgid), 0, 32);
  108. }
  109. /**
  110. * 玩家登陆的时候初始化sig
  111. * @param Req $req
  112. */
  113. public static function InitSig($req) {
  114. $paras = array();
  115. $paras["openid"] = $req->uid;
  116. $paras["ep"] = HttpUtil::getClientEP();
  117. $paras["ts"] = now();
  118. $self_url_path = "atomsoft.com";
  119. $siginfo = new SigInfo();
  120. $siginfo->uid = $req->uid;
  121. $siginfo->zoneid = $req->zoneid;
  122. $siginfo->sig = self::makeSig('post', $self_url_path, $paras, PROJECTNAME);
  123. $siginfo->msgnum = 0;
  124. return $siginfo;
  125. }
  126. /**
  127. * 生成签名
  128. *
  129. * @param string $method 请求方法 "get" or "post"
  130. * @param string $url_path
  131. * @param array $params 表单参数
  132. * @param string $secret 密钥
  133. */
  134. public static function makeSig($method, $url_path, $params, $secret) {
  135. $mk = self::makeSource($method, $url_path, $params);
  136. $my_sign = hash_hmac("sha1", $mk, strtr($secret, '-_', '+/'), true);
  137. $my_sign = base64_encode($my_sign);
  138. return $my_sign;
  139. }
  140. private static function makeSource($method, $url_path, $params) {
  141. $strs = strtoupper($method) . '&' . rawurlencode($url_path) . '&';
  142. ksort($params);
  143. $query_string = array();
  144. foreach ($params as $key => $val) {
  145. array_push($query_string, $key . '=' . $val);
  146. }
  147. $query_string = join('&', $query_string);
  148. return $strs . str_replace('~', '%7E', rawurlencode($query_string));
  149. }
  150. }