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

Popular posts from this blog

python - TypeError: start must be a integer -

c# - DevExpress RepositoryItemComboBox BackColor property ignored -

django - Creating multiple model instances in DRF3 -