fix(security): wallet race conditions - FOR UPDATE + atomic claims on payments, webhooks, bonuses
This commit is contained in:
@@ -96,24 +96,26 @@ try {
|
||||
// ============================================================
|
||||
global $con;
|
||||
|
||||
// 4) التحقق من السجل في قاعدة البيانات
|
||||
$chk = $con->prepare("SELECT status, user_id, amount, payment_method FROM paymentsLogSyria WHERE order_ref = :ref LIMIT 1");
|
||||
// بدء المعاملة أولاً (قبل SELECT للحماية من السباق)
|
||||
$con->beginTransaction();
|
||||
|
||||
// 4) التحقق من السجل في قاعدة البيانات مع FOR UPDATE
|
||||
$chk = $con->prepare("SELECT status, user_id, amount, payment_method FROM paymentsLogSyria WHERE order_ref = :ref LIMIT 1 FOR UPDATE");
|
||||
$chk->execute([':ref' => $transactionID]);
|
||||
$payment = $chk->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$payment) {
|
||||
$con->rollBack();
|
||||
printFailure($lang === 'ar' ? "لم يتم العثور على السجل." : "Payment row not found");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ((int)$payment['status'] === 1) {
|
||||
$con->rollBack();
|
||||
printSuccess(['message' => 'Already confirmed', 'data' => ['order_ref' => $transactionID]]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// بدء المعاملة (Transaction)
|
||||
$con->beginTransaction();
|
||||
|
||||
try {
|
||||
// أ) تحديث حالة الدفع في السجل
|
||||
$stmtUpdate = $con->prepare("UPDATE `paymentsLogSyria` SET status = 1, updated_at = NOW() WHERE order_ref = :ref");
|
||||
|
||||
Reference in New Issue
Block a user