php - Dealing with concurrent requests in CodeIgniter -
say have created online banking system using codeigniter/php , mysql, , have following withdraw money bank account:
function withdraw($user_id, $amount) { $amount = (int)$amount; // make sure have enough in bank account $balance = $this->db->where('user_id', $user_id) ->get('bank_account')->balance; if ($balance < $amount) { return false; } // take money out of bank $this->db->where('user_id', $user_id) ->set('balance', 'balance-'.$amount, false) ->update('bank_account'); // put money in wallet $this->db->where('user_id', $user_id) ->set('balance', 'balance+'.$amount, false) ->update('wallet'); return true; }
first, check see if user can perform withdrawl, subtract account, , add wallet.
the problem can send out multiple requests @ pretty exact same time (this trivial using curl
). each request gets own thread, run concurrently. such, each performs check see if have enough in bank (which do), , each performs withdrawal. result, if start balance of 100, , send out 2 curl
requests cause such withdrawal of 100 @ same time, end 200 in wallet , -100 in bank account, should not possible.
what correct "codeigniter" way solve kind of toctou vulnerability?
i'd set storage engine of bank_account
, wallet
tables innodb has transaction support , include for update clause in select statement lock bank_account
table duration of transaction.
the code following.
function withdraw($user_id, $amount) { $amount = (int)$amount; $this->db->trans_start(); $query = $this->db->query("select * bank_account user_id = $user_id , balance >= $amount update"); if($query->num_rows() === 0) { $this->db->trans_complete(); return false; } $this->db->where('user_id', $user_id) ->set('balance', 'balance-'.$amount, false) ->update('bank_account'); $this->db->where('user_id', $user_id) ->set('balance', 'balance+'.$amount, false) ->update('wallet'); $this->db->trans_complete(); return true; }
Comments
Post a Comment