找回密码
 注册账号

QQ登录

只需一步,快速开始

《泰拉瑞亚下载-1.4.2.3版》 泰拉瑞亚服务器 - MOD模组下载

入驻泰拉战网 新手指引 - 升级 - 师徒

泰拉瑞亚合成表 泰拉卡牌 - 泰拉江湖 - 泰拉刺客

联系泰拉开发组👈进入 积分市场 - 房产交易 - 水晶获取

查看: 1913|回复: 0

[原生PHP] 游戏中商店系统formHash的实现

[复制链接]

262

主题

124

回帖

9

广播

业务站长

积分
166
泰拉
180
水晶
2
铜钥匙
0
银钥匙
0
金钥匙
0

【江湖新秀】【我是小土豪】【宝剑回鞘】【泰拉达人】【奥运选手】

发表于 2019-10-21 11:52:24 | 显示全部楼层 |阅读模式
问题重现
在我们的项目中,有一个商店购买的页面,流程是这样的:  选择道具  ----->  点击购买   -------> 获得道具 ------> 扣除银币
如果玩家在一秒钟并发的请求这个URL,  如果他有100个银币,只可以买10个道具,由于并发的问题,他还可以买100个道具,到时候,他的银币的数量可能扣除为负数。这样,对游戏来说,是非常严重的问题。
并发的原理是这样的: 当玩家第一次购买道具的的时候,读取玩家的余额,如果大于道具的价格,系统把道具给玩家,然后在扣除玩家的余额。在我我把道具给了玩家过程中,由于大量的请求过来,还没有来得及把玩家的钱扣除,所以,导致了玩家买到了更多的东西

问题所在
如果扣“除银币”在“获得道具”之前完成,就基本上可以避免了这种问题,但是,由于我们道具的特殊设定,不能先扣除银币,所以不能这样做
这样,就只能避免玩家重复的提交同一个买道具的URL,产生了大量的并发。方法是,URL上面加一个formHash,每次都生成一个新的formHash.那么就防止了页面多次提交了。


formHash的生成代码
formHash保存在memcache中


  1. // 生成新的 formHash
  2. public function refreshFormHash($formName)
  3. {
  4.     // 生成随机码
  5.     $formHash = md5('VoyageMobile:' . date('md') . ':' . mt_rand() . ':' . $formName);

  6.     $cacheObj = Com_Cache::getInstance('Memcache');
  7.     $cacheKey = 'formHash:' . $formName;

  8.     // 将 formHash 写入到 Memcache 中
  9.     $cacheObj->set($cacheKey, $formHash);

  10.     // 传出到模板中
  11.     $this->assign('formHash', $formHash);

  12.     return $formHash;
  13. }
复制代码


formHash的验证
  1. /**
  2. * 验证 formHash 是否正确
  3. *
  4. * @param string $formName
  5. * @param mixed $formHashGet
  6. * @param bool $clear 是否取完即清除
  7. * @return bool
  8. */
  9. public function validFormHash($formName, $formHashGet = null, $clear = true)
  10. {<br>      // 页面中传过来的formHash
  11.     if ($formHashGet === null) {
  12.         $formHashGet = $this->getx('formHash');
  13.     }

  14.     $cacheObj = Com_Cache::getInstance('Memcache');
  15.     $cacheKey = 'formHash:' . $formName;

  16.     $formHash = $cacheObj->get($cacheKey);

  17.     // 取完即清除(formHash只能用一次)
  18.     $clear && $cacheObj->delete($cacheKey);

  19.     return $formHash == $formHashGet ? true : false;
  20. }
复制代码


formHash的使用
在道具购买的首页中,系统生成一个formHash.


  1. public function shopIndex()
  2. {
  3.   // 生成道具的列表

  4.   // 生成formHash
  5.   $this->refreshFormHash();  
  6.      
  7. }
复制代码


formHash的验证
在购买道具的函数中,必须验证formHash,而且,必须生成新的formHash,并分配到页面中

  1.     /**
  2.      * 购买提交
  3.      */
  4.     public function purchaseAction()
  5.     {
  6.         // 验证请求合法性
  7.         if (! $this->validFormHash('bmItem')) {
  8.             $this->vRedirect('/main/?err=Invalid_Request_FormHash');
  9.         }

  10.         // 重新刷新 formHash
  11.        $this->refreshFormHash('bmItem');

  12.         //  购买流程
  13. }
复制代码


   注意问题
   某些页面是ajax请求,不刷新页面,这时候把新生成的formHash 动态的在页面中生成。

获得 小穷神卡 一张

卡片说明:曲奇饼 被 [没有钱的倾听酱] 附体!失去了 39 泰拉.

卡片效果:损失 39 泰拉

慵懒~慵懒~
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

QQ|友链申请|Archiver|手机版|小黑屋|游芯沙盒 ( 陕ICP备11006283号-1 )

GMT+8, 2024-5-20 03:09 , Processed in 0.112214 second(s), 36 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表