formHash的实现

问题重现

在我们的项目中,有一个商店购买的页面,流程是这样的:  选择道具  ----->  点击购买   -------> 获得道具 ------> 扣除银币

如果玩家在一秒钟并发的请求这个URL,  如果他有100个银币,只可以买10个道具,由于并发的问题,他还可以买100个道具,到时候,他的银币的数量可能扣除为负数。这样,对游戏来说,是非常严重的问题。

并发的原理是这样的: 当玩家第一次购买道具的的时候,读取玩家的余额,如果大于道具的价格,系统把道具给玩家,然后在扣除玩家的余额。在我我把道具给了玩家过程中,由于大量的请求过来,还没有来得及把玩家的钱扣除,所以,导致了玩家买到了更多的东西

问题所在

如果扣“除银币”在“获得道具”之前完成,就基本上可以避免了这种问题,但是,由于我们道具的特殊设定,不能先扣除银币,所以不能这样做

这样,就只能避免玩家重复的提交同一个买道具的URL,产生了大量的并发。方法是,URL上面加一个formHash,每次都生成一个新的formHash.那么就防止了页面多次提交了。

 

formHash的生成代码

formHash保存在memcache中

?
// 生成新的 formHash
public  function  refreshFormHash( $formName )
{
     // 生成随机码
     $formHash  = md5( 'VoyageMobile:'  . date ( 'md' ) . ':'  . mt_rand() . ':'  . $formName );
 
     $cacheObj  = Com_Cache::getInstance( 'Memcache' );
     $cacheKey  = 'formHash:'  . $formName ;
 
     // 将 formHash 写入到 Memcache 中
     $cacheObj ->set( $cacheKey , $formHash );
 
     // 传出到模板中
     $this ->assign( 'formHash' , $formHash );
 
     return  $formHash ;
}

  

formHash的验证
?
/**
  * 验证 formHash 是否正确
  *
  * @param string $formName
  * @param mixed $formHashGet
  * @param bool $clear 是否取完即清除
  * @return bool
  */
public  function  validFormHash( $formName , $formHashGet  = null, $clear  = true)
{   // 页面中传过来的formHash
     if  ( $formHashGet  === null) {
         $formHashGet  = $this ->getx( 'formHash' );
     }
 
     $cacheObj  = Com_Cache::getInstance( 'Memcache' );
     $cacheKey  = 'formHash:'  . $formName ;
 
     $formHash  = $cacheObj ->get( $cacheKey );
 
     // 取完即清除(formHash只能用一次)
     $clear  && $cacheObj -> delete ( $cacheKey );
 
     return  $formHash  == $formHashGet  ? true : false;
}

  

formHash的使用

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

?
public  function  shopIndex()
{
   // 生成道具的列表
 
   // 生成formHash
   $this ->refreshFormHash(); 
     
}

  

formHash的验证

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

?
     /**
      * 购买提交
      */
     public  function  purchaseAction()
     {
         // 验证请求合法性
         if  (! $this ->validFormHash( 'bmItem' )) {
             $this ->vRedirect( '/main/?err=Invalid_Request_FormHash' );
         }
 
         // 重新刷新 formHash
        $this ->refreshFormHash( 'bmItem' );
 
         //  购买流程
}

  

 

   注意问题

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

   当客户端有传值,但服务端查不到时(可能是 Memcache 意外重启),为保证玩家体验,则直接当成验证通过

   ajax提交失败也要更新formHash 见我文章xxxx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值