123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- <?php
- namespace loyalsoft;
- /**
- * Description of PreProc
- * 预处理流程
- * 提供数据包预处理机制、加解密、合法化判定等等
- * @author jgao
- */
- class PreProc {
- /**
- * tk判定
- * @param Req $req
- * @return int 返回操作结果,0:成功,其余为错误码
- */
- public static function tk($req) {
- my_Assert(!config::Inst()->isBaned($req->uid), ErrCode::err_server_updating); # 检查封号
- // $ret = self::checkVersion($req); # 检查客户端版本 -王刚 已经于2020.4.29 废弃, 改为提前检查版本号了.
- // my_Assert(ErrCode::ok == $ret, $ret); # 客户端版本过低
- # 检查是否处于更新阶段,暂停对玩家请求的响应。
- if (GAME_ONLINE # 外网
- && self::isUpdating() # 更新
- && !config::Inst()->isTester($req->uid)) { # 排除测试号
- return ErrCode::err_server_updating;
- }
- $ssd = GameConfig::service_schedule_getItem(1); # 服务计划(固定只有1条)
- if (now() > $ssd->startts && now() < $ssd->endts) { # 在维护期间
- // return ErrCode::err_server_maintaining;
- Err(ErrCode::err_server_maintaining, $ssd->reason);
- }
- // if (!GAME_ONLINE || config::Inst()->isTester($req->uid)) { # 内网不做token校验操作
- return ErrCode::ok;
- // }
- if ($req->cmd == CmdCode::cmd_user_getzonelist) { # 如果是获取分区列表的消息初始化tk信息,不做校验
- $siginfo = SigInfo::InitSig($req); # 初始化sigInfo
- $req->sig = $siginfo->sig; # 每次resp会从req上取sig值返回
- $req->msgid = PreProc::createMsgId($siginfo); # 初始化msgid
- $siginfo->msgid = SigInfo::calcMsgid($siginfo, $req); # sigInfo和本次的$req身上的msgid,用于下次消息校验,
- self::updateUserSigInfo($req, $siginfo); # 写入Cmem,下次登录的时候校验
- return ErrCode::ok;
- }
- # 其余消息,全部进行校验
- $siginfo = self::getUserSigInfo($req); # 1.从Cmem读取证书验证信息
- if ($siginfo == null) {
- return ErrCode::err_signo;
- }
- if ($req->sig != $siginfo->sig) { # 2.如果一次性证书不一致,则证明已经在其他地方登录
- return ErrCode::err_anotherlogin;
- }
- if ($siginfo->msgid != SigInfo::calcMsgid($siginfo, $req)) { # 3.如果消息id错位,则证明该条消息非法
- return ErrCode::err_illegal;
- }
- if (now() - $req->ts > OFFSET_MSGTIME) { # 4.如果服务端客户端时间戳超过规定误差,则消息非法
- return ErrCode::err_outtime;
- }
- # 更新siginfo
- $siginfo->msgnum++; # 消息编号递增
- $req->msgid = PreProc::createMsgId($siginfo); # ...
- $siginfo->msgid = SigInfo::calcMsgid($siginfo, $req); # 计算新的
- self::updateUserSigInfo($req, $siginfo); # 回写siginfo
- return ErrCode::ok; # 返回操作结果,0:成功,其余为错误码
- }
- public static function createMsgId($siginfo) {
- $temp = 8888 - $siginfo->msgnum;
- return substr(md5(substr($siginfo->uid, 2, 20) . $temp . substr($siginfo->sig, 5, 15)), 7, 23);
- }
- // /**
- // * 检查客户端版本是否需要强制更新
- // * @param Req $req
- // * @return int ErrCode
- // */
- // public static function checkVersion($req) {
- // $clientVer = $req->clientVer;
- // $ClientVerArr = explode('.', $clientVer);
- // $ServerVerArr = explode('.', glc()->clientVer);
- //
- // if ($ClientVerArr[0] < $ServerVerArr[0] # # 主版本号小
- // || $ClientVerArr[1] < $ServerVerArr[1]) { # 次版本号小
- // $req->updateInfo = GameConfig::clientVersionHistory_getItem(glc()->clientVer);
- // $req->updateInfo->newVer = glc()->clientVer;
- // return ErrCode::clientversionlow_err; # 返回错误码,强制更新1
- // }
- //
- // if ($ClientVerArr[0] == $ServerVerArr[0] # 主版本号相同
- // && $ClientVerArr[1] == $ServerVerArr[1] # 次版本号相同
- // && $ClientVerArr[2] < $ServerVerArr[2] && # # 修订版本号不一致, 提示更新
- // ($req->cmd == CmdCode::cmd_user_getzonelist # 只在拉取分区列表的时候提示下得了.又不是强更
- // || $req->cmd == CmdCode::cmd_user_gameconstinfo)) { # 或者是拉取常量信息也行
- // $req->updateInfo = GameConfig::clientVersionHistory_getItem(glc()->clientVer); # 提示更新,可以暂不更新,不返回错误码了
- // $req->updateInfo->newVer = glc()->clientVer;
- // }
- // return ErrCode::ok;
- // }
- /**
- * 返回是否处于更新中
- * @return boolean
- */
- public static function isUpdating() {
- $ts = now();
- if ($ts > glc()->updatingBeginTs && $ts < glc()->updatingEndTs) {
- return true;
- }
- return false;
- }
- /**
- * 把玩家的SigInfo写入数据库
- * @param Req $req
- * @param SigInfo $siginfo
- */
- public static function updateUserSigInfo($req, $siginfo) {
- gMem()->set(MemKey_User::Sig($req->zoneid, $siginfo->uid), $siginfo);
- }
- /**
- * 从Cmem中读取玩家的SigInfo数据
- * @param Req $req
- * @return SigInfo
- */
- public static function getUserSigInfo($req) {
- return gMem()->get(MemKey_User::Sig($req->zoneid, $req->uid));
- }
- }
- /**
- * 校验信息
- */
- class SigInfo {
- public $uid;
- public $zoneid;
- public $sig;
- public $msgnum;
- public $msgid;
- /**
- *
- * @param SigInfo $siginfo
- * @param Req $req
- */
- public static function calcMsgid($siginfo, $req) {
- return substr(md5($siginfo->sig . $req->msgid), 0, 32);
- }
- /**
- * 玩家登陆的时候初始化sig
- * @param Req $req
- */
- public static function InitSig($req) {
- $paras = array();
- $paras["openid"] = $req->uid;
- $paras["ep"] = HttpUtil::getClientEP();
- $paras["ts"] = now();
- $self_url_path = "atomsoft.com";
- $siginfo = new SigInfo();
- $siginfo->uid = $req->uid;
- $siginfo->zoneid = $req->zoneid;
- $siginfo->sig = self::makeSig('post', $self_url_path, $paras, PROJECTNAME);
- $siginfo->msgnum = 0;
- return $siginfo;
- }
- /**
- * 生成签名
- *
- * @param string $method 请求方法 "get" or "post"
- * @param string $url_path
- * @param array $params 表单参数
- * @param string $secret 密钥
- */
- public static function makeSig($method, $url_path, $params, $secret) {
- $mk = self::makeSource($method, $url_path, $params);
- $my_sign = hash_hmac("sha1", $mk, strtr($secret, '-_', '+/'), true);
- $my_sign = base64_encode($my_sign);
- return $my_sign;
- }
- private static function makeSource($method, $url_path, $params) {
- $strs = strtoupper($method) . '&' . rawurlencode($url_path) . '&';
- ksort($params);
- $query_string = array();
- foreach ($params as $key => $val) {
- array_push($query_string, $key . '=' . $val);
- }
- $query_string = join('&', $query_string);
- return $strs . str_replace('~', '%7E', rawurlencode($query_string));
- }
- }
|