PreProc.php 8.2 KB

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