setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Create tables if they don't exist (including pin_setup table) $pdo->exec(" CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) UNIQUE NOT NULL, email VARCHAR(100) UNIQUE NOT NULL, tier VARCHAR(20) DEFAULT 'Basic', package VARCHAR(50) DEFAULT 'Starter', balance DECIMAL(10, 2) DEFAULT 5000.00, pin_hash VARCHAR(255) DEFAULT NULL, pin_setup_complete BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS pin_setup ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, pin_hash VARCHAR(255) NOT NULL, setup_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS transactions ( id INT AUTO_INCREMENT PRIMARY KEY, sender_id INT NOT NULL, recipient_id INT NOT NULL, amount DECIMAL(10, 2) NOT NULL, message TEXT, status ENUM('pending', 'completed', 'failed') DEFAULT 'pending', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, completed_at TIMESTAMP NULL ); CREATE TABLE IF NOT EXISTS balance_history ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, transaction_id INT NULL, amount DECIMAL(10, 2) NOT NULL, balance_before DECIMAL(10, 2) NOT NULL, balance_after DECIMAL(10, 2) NOT NULL, type ENUM('transfer_sent', 'transfer_received', 'deposit', 'withdrawal'), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); "); // Check if demo user exists, if not create it $stmt = $pdo->prepare("SELECT id, pin_setup_complete FROM users WHERE username = ?"); $stmt->execute([$_SESSION['username']]); $user = $stmt->fetch(); if (!$user) { $stmt = $pdo->prepare("INSERT INTO users (username, email, tier, package, balance) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([ $_SESSION['username'], $_SESSION['email'], $_SESSION['tier'], $_SESSION['package'], $_SESSION['balance'] ]); $user_id = $pdo->lastInsertId(); // Set pin_setup_complete to false for new users $_SESSION['pin_setup_complete'] = false; } else { $_SESSION['pin_setup_complete'] = (bool)$user['pin_setup_complete']; } } catch (PDOException $e) { // If database connection fails, continue with session data only error_log("Database connection failed: " . $e->getMessage()); $pdo = null; $_SESSION['pin_setup_complete'] = $_SESSION['pin_setup_complete'] ?? false; } // Get user data from session $username = $_SESSION['username']; $email = $_SESSION['email']; $tier = $_SESSION['tier']; $package = $_SESSION['package']; $balance = $_SESSION['balance']; $total_deposits = $_SESSION['total_deposits']; $total_withdrawals = $_SESSION['total_withdrawals']; $rewards = $_SESSION['rewards']; $pin_setup_complete = $_SESSION['pin_setup_complete']; $earnings = $total_deposits - $total_withdrawals; // Process PIN setup if form is submitted if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['setup_pin'])) { $new_pin = $_POST['new_pin']; $confirm_pin = $_POST['confirm_pin']; // Validate PINs if (strlen($new_pin) !== 4 || !is_numeric($new_pin)) { $_SESSION['error'] = "PIN must be exactly 4 digits."; header("Location: transfer.php"); exit; } if ($new_pin !== $confirm_pin) { $_SESSION['error'] = "PINs do not match."; header("Location: transfer.php"); exit; } // Check if PIN is not a simple pattern if (preg_match('/^(\d)\1{3}$/', $new_pin) || preg_match('/^0123|1234|2345|3456|4567|5678|6789|7890$/', $new_pin) || preg_match('/^0987|9876|8765|7654|6543|5432|4321|3210$/', $new_pin)) { $_SESSION['error'] = "Please choose a more secure PIN. Avoid simple patterns."; header("Location: transfer.php"); exit; } if ($pdo) { try { // Hash the PIN (in a real application, use password_hash with a proper algorithm) $pin_hash = password_hash($new_pin, PASSWORD_DEFAULT); // Update user record with PIN hash and mark setup as complete $stmt = $pdo->prepare("UPDATE users SET pin_hash = ?, pin_setup_complete = TRUE WHERE username = ?"); $stmt->execute([$pin_hash, $username]); // Record PIN setup in history $stmt = $pdo->prepare("INSERT INTO pin_setup (user_id, pin_hash) SELECT id, ? FROM users WHERE username = ?"); $stmt->execute([$pin_hash, $username]); // Update session $_SESSION['pin_setup_complete'] = true; $pin_setup_complete = true; $_SESSION['success'] = "PIN setup successful! You can now make transfers."; } catch (Exception $e) { $_SESSION['error'] = "PIN setup failed: " . $e->getMessage(); } } else { // Fallback to session-only processing if database is not available $_SESSION['pin_hash'] = $new_pin; // In a real app, this would be hashed $_SESSION['pin_setup_complete'] = true; $pin_setup_complete = true; $_SESSION['success'] = "PIN setup successful! You can now make transfers."; } header("Location: transfer.php"); exit; } // Process transfer if form is submitted if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['transfer'])) { // Check if PIN is set up if (!$pin_setup_complete) { $_SESSION['error'] = "You must set up your security PIN before making transfers."; header("Location: transfer.php"); exit; } $recipient_username = $_POST['recipient']; $amount = floatval($_POST['amount']); $pin = $_POST['pin']; $message = $_POST['message'] ?? ''; // Validate inputs if (empty($recipient_username) || $amount <= 0 || strlen($pin) !== 4 || !is_numeric($pin)) { $_SESSION['error'] = "Invalid input data."; header("Location: transfer.php"); exit; } if ($pdo) { try { // Begin transaction $pdo->beginTransaction(); // Get sender info $stmt = $pdo->prepare("SELECT id, balance, pin_hash FROM users WHERE username = ?"); $stmt->execute([$username]); $sender = $stmt->fetch(PDO::FETCH_ASSOC); if (!$sender) { throw new Exception("Sender not found."); } // Verify PIN if (!password_verify($pin, $sender['pin_hash'])) { throw new Exception("Invalid PIN."); } // Check if sender has sufficient balance if ($sender['balance'] < $amount) { throw new Exception("Insufficient balance."); } // Get recipient info $stmt = $pdo->prepare("SELECT id, username, balance FROM users WHERE username = ?"); $stmt->execute([$recipient_username]); $recipient = $stmt->fetch(PDO::FETCH_ASSOC); if (!$recipient) { // Create recipient if they don't exist (for demo purposes) $stmt = $pdo->prepare("INSERT INTO users (username, email, balance) VALUES (?, ?, ?)"); $stmt->execute([$recipient_username, $recipient_username . '@example.com', 5000.00]); $recipient_id = $pdo->lastInsertId(); $stmt = $pdo->prepare("SELECT id, username, balance FROM users WHERE id = ?"); $stmt->execute([$recipient_id]); $recipient = $stmt->fetch(PDO::FETCH_ASSOC); } if ($sender['id'] === $recipient['id']) { throw new Exception("Cannot transfer to yourself."); } // Create transaction record $stmt = $pdo->prepare("INSERT INTO transactions (sender_id, recipient_id, amount, message, status) VALUES (?, ?, ?, ?, 'completed')"); $stmt->execute([$sender['id'], $recipient['id'], $amount, $message]); $transaction_id = $pdo->lastInsertId(); // Update sender balance $new_sender_balance = $sender['balance'] - $amount; $stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?"); $stmt->execute([$new_sender_balance, $sender['id']]); // Record sender balance change $stmt = $pdo->prepare("INSERT INTO balance_history (user_id, transaction_id, amount, balance_before, balance_after, type) VALUES (?, ?, ?, ?, ?, 'transfer_sent')"); $stmt->execute([$sender['id'], $transaction_id, -$amount, $sender['balance'], $new_sender_balance]); // Update recipient balance $new_recipient_balance = $recipient['balance'] + $amount; $stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?"); $stmt->execute([$new_recipient_balance, $recipient['id']]); // Record recipient balance change $stmt = $pdo->prepare("INSERT INTO balance_history (user_id, transaction_id, amount, balance_before, balance_after, type) VALUES (?, ?, ?, ?, ?, 'transfer_received')"); $stmt->execute([$recipient['id'], $transaction_id, $amount, $recipient['balance'], $new_recipient_balance]); // Update transaction status to completed $stmt = $pdo->prepare("UPDATE transactions SET status = 'completed', completed_at = NOW() WHERE id = ?"); $stmt->execute([$transaction_id]); // Commit transaction $pdo->commit(); // Update session balance $_SESSION['balance'] = $new_sender_balance; $balance = $new_sender_balance; $_SESSION['success'] = "Transfer of KES " . number_format($amount, 2) . " to @$recipient_username was successful!"; // Store notification in session if (!isset($_SESSION['notifications'])) { $_SESSION['notifications'] = []; } $_SESSION['notifications'][] = [ 'type' => 'transfer_sent', 'to' => $recipient_username, 'amount' => $amount, 'message' => $message, 'timestamp' => time() ]; } catch (Exception $e) { $pdo->rollBack(); $_SESSION['error'] = "Transfer failed: " . $e->getMessage(); } } else { // Fallback to session-only processing if database is not available if (!$pin_setup_complete || $pin !== ($_SESSION['pin_hash'] ?? '')) { $_SESSION['error'] = "Invalid PIN or PIN not set up."; } else if ($amount > $balance) { $_SESSION['error'] = "Insufficient balance."; } else { // Update session balance $_SESSION['balance'] = $balance - $amount; $balance = $_SESSION['balance']; $_SESSION['success'] = "Transfer of KES " . number_format($amount, 2) . " to @$recipient_username was successful!"; // Store transaction in session if (!isset($_SESSION['transactions'])) { $_SESSION['transactions'] = []; } $_SESSION['transactions'][] = [ 'recipient' => $recipient_username, 'amount' => $amount, 'message' => $message, 'timestamp' => time(), 'status' => 'completed' ]; } } header("Location: transfer.php"); exit; } // Get transaction history $transactions = []; if ($pdo) { try { $stmt = $pdo->prepare(" SELECT t.*, sender.username as sender_username, recipient.username as recipient_username, CASE WHEN t.sender_id = u.id THEN 'sent' ELSE 'received' END as direction FROM transactions t JOIN users sender ON t.sender_id = sender.id JOIN users recipient ON t.recipient_id = recipient.id JOIN users u ON (t.sender_id = u.id OR t.recipient_id = u.id) WHERE u.username = ? ORDER BY t.created_at DESC LIMIT 10 "); $stmt->execute([$username]); $transactions = $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { error_log("Error fetching transactions: " . $e->getMessage()); } } else if (isset($_SESSION['transactions'])) { // Fallback to session transactions $transactions = $_SESSION['transactions']; } // Get current balance from database if available if ($pdo) { try { $stmt = $pdo->prepare("SELECT balance, pin_setup_complete FROM users WHERE username = ?"); $stmt->execute([$username]); $user_data = $stmt->fetch(PDO::FETCH_ASSOC); if ($user_data) { $balance = $user_data['balance']; $pin_setup_complete = (bool)$user_data['pin_setup_complete']; $_SESSION['balance'] = $balance; $_SESSION['pin_setup_complete'] = $pin_setup_complete; } } catch (PDOException $e) { error_log("Error fetching balance: " . $e->getMessage()); } } ?> Japanese Motors — Transfer
Jmotors
💸

Send Money

Transfer to another Jmotors user
Available Balance:
KES
Security PIN Required

You need to set up a security PIN before making transfers.

>
📜

Transfer History

Your recent transfer activity
KES
""

No transfers yet

Your transfer history will appear here