PHP WebShell
Текущая директория: /var/www/bitcardoApp/models/auth
Просмотр файла: register_process.php
<?php
declare(strict_types=1);
// Session cookie hardening (must be set before session_start)
session_set_cookie_params([
'httponly' => true,
'secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
'samesite' => 'Lax',
]);
session_start();
require '../../config/db_config.php'; // uses $conn (MySQLi)
// Show errors during development (remove on production)
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
/**
* Generate a unique 12-digit wallet_add and create the user's NGN wallet.
*
* @throws RuntimeException on failure
* @return string The created wallet_add
*/
function createNgnWallet(mysqli $conn, int $userId): string
{
// If a wallet already exists for NGN, return it (idempotent safety)
$check = $conn->prepare("SELECT wallet_add FROM user_wallets WHERE user_id = ? AND coin = 'NGN' LIMIT 1");
$check->bind_param('i', $userId);
$check->execute();
$check->bind_result($existingAdd);
if ($check->fetch()) {
$check->close();
return $existingAdd;
}
$check->close();
// Generate unique 12-digit wallet_add
$walletAdd = '';
$probe = $conn->prepare("SELECT 1 FROM user_wallets WHERE wallet_add = ? LIMIT 1");
do {
// 12-digit numeric string (leading zeros allowed)
$walletAdd = str_pad((string)random_int(0, 999999999999), 12, '0', STR_PAD_LEFT);
$probe->bind_param('s', $walletAdd);
$probe->execute();
$probe->store_result();
$exists = $probe->num_rows > 0;
} while ($exists);
$probe->close();
// Insert NGN wallet
$insert = $conn->prepare("
INSERT INTO user_wallets
(cwallet_id, user_id, wallet_add, bank_name, wallet_qr, coin, icon, balance, type, label, wallet_status, updated_at, created_at)
VALUES
(NULL, ?, ?, 'Bitcardo', NULL, 'NGN', 'ngn.png', '0.00', 'fiat', 'Naira Wallet', 'active', NOW(), NOW())
");
$insert->bind_param('is', $userId, $walletAdd);
$insert->execute();
$insert->close();
return $walletAdd;
}
try {
if (!isset($conn) || !($conn instanceof mysqli)) {
throw new RuntimeException('Database connection not initialized.');
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Location: ../../auth/register.php');
exit;
}
// Gather inputs
$first = trim($_POST['first_name'] ?? '');
$last = trim($_POST['last_name'] ?? '');
$emailInput = trim($_POST['email'] ?? '');
$phoneInput = trim($_POST['phone'] ?? '');
$password = $_POST['password'] ?? '';
$recaptchaResponse = $_POST['g-recaptcha-response'] ?? '';
// Preserve original inputs for form re-fill
$_SESSION['form_data'] = [
'first' => $first,
'last' => $last,
'email' => $emailInput,
'phone' => $phoneInput,
];
// Basic validation
if ($first === '' || $last === '' || $emailInput === '' || $phoneInput === '' || $password === '') {
$_SESSION['error'] = 'Please fill in all required fields.';
header('Location: ../../auth/register.php');
exit;
}
if (!filter_var($emailInput, FILTER_VALIDATE_EMAIL)) {
$_SESSION['error'] = 'Please enter a valid email address.';
header('Location: ../../auth/register.php');
exit;
}
if (!preg_match('/^[0-9+\-\s()]{7,20}$/', $phoneInput)) {
$_SESSION['error'] = 'Please enter a valid phone number.';
header('Location: ../../auth/register.php');
exit;
}
if (!preg_match('/^(?=.*[A-Z])(?=.*\d).{8,}$/', $password)) {
$_SESSION['error'] = 'Password must be at least 8 characters, include a number and an uppercase letter.';
header('Location: ../../auth/register.php');
exit;
}
// Normalize for storage/uniqueness
function normalize_email($input) {
$input = trim($input);
$parts = explode('@', $input, 2);
if (count($parts) !== 2) return $input; // or handle invalid address
[$local, $domain] = $parts;
return $local . '@' . strtolower($domain);
}
$email = normalize_email($emailInput);
$phone = preg_replace('/\D+/', '', $phoneInput); // digits only
// Lightweight throttling by IP (session-based)
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$key = 'reg_attempts_' . $ip;
$_SESSION[$key] = ($_SESSION[$key] ?? 0) + 1;
if ($_SESSION[$key] > 10) {
$_SESSION['error'] = 'Too many attempts. Please try again later.';
header('Location: ../../auth/register.php');
exit;
}
// reCAPTCHA verification (use constant if available; fallback to your current value)
$recaptchaSecret = defined('RECAPTCHA_SECRET')
? RECAPTCHA_SECRET
: '6Lf4qEwrAAAAAO_OSKyBcGLPRtxy___IZMTLAwxP';
if ($recaptchaResponse === '') {
$_SESSION['error'] = 'Captcha verification failed.';
header('Location: ../../auth/register.php');
exit;
}
$verifyUrl = 'https://www.google.com/recaptcha/api/siteverify';
$postFields = http_build_query([
'secret' => $recaptchaSecret,
'response' => $recaptchaResponse,
'remoteip' => $_SERVER['REMOTE_ADDR'] ?? null,
]);
$captchaOk = false;
if (function_exists('curl_init')) {
$ch = curl_init($verifyUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postFields,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
$result = curl_exec($ch);
curl_close($ch);
if ($result !== false) {
$decoded = json_decode($result, true);
$captchaOk = !empty($decoded['success']);
}
} else {
$result = @file_get_contents($verifyUrl . '?' . $postFields);
if ($result !== false) {
$decoded = json_decode($result, true);
$captchaOk = !empty($decoded['success']);
}
}
if (!$captchaOk) {
$_SESSION['error'] = 'Captcha verification failed.';
header('Location: ../../auth/register.php');
exit;
}
// Begin transaction for atomic user + wallet creation
$conn->begin_transaction();
// Prevent duplicate email/phone (normalized)
$checkSql = "SELECT user_id FROM `users` WHERE email = ? OR phone = ? LIMIT 1";
$stmt = $conn->prepare($checkSql);
$stmt->bind_param('ss', $email, $phone);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows > 0) {
$stmt->close();
$conn->rollback();
$_SESSION['error'] = 'An account with this email or phone already exists.';
header('Location: ../../auth/register.php');
exit;
}
$stmt->close();
// Hash the password
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
// Insert user (with status + created_at)
$insertUser = $conn->prepare("
INSERT INTO `users`
(email, phone, password_hash, first_name, last_name, user_status, created_at)
VALUES
(?, ?, ?, ?, ?, 'active', NOW())
");
$insertUser->bind_param('sssss', $email, $phone, $passwordHash, $first, $last);
$insertUser->execute();
$newUserId = (int)$conn->insert_id;
$insertUser->close();
// Create NGN wallet
createNgnWallet($conn, $newUserId);
// All good
$conn->commit();
// -------- NEW: make sure challenge page has the identity it needs --------
session_regenerate_id(true);
$_SESSION['user_id'] = $newUserId;
$_SESSION['email'] = $email; // <-- important for /auth/challenge.php (email OTP fallback)
$_SESSION['first_name'] = $first ?? '';
$_SESSION['last_name'] = $last ?? '';
$_SESSION['loggedIn'] = true;
unset($_SESSION['form_data'], $_SESSION['error']);
// ------------------------------------------------------------------------
// Allow skipping OTP this first session, and show "Trust this device?" banner
$_SESSION['first_session_grace'] = 1;
$_SESSION['show_trust_banner'] = 1;
// Redirect (keep your current destination)
header('Location: ../../user/dashboard/index.php');
exit;
} catch (Throwable $e) {
if (isset($conn) && $conn instanceof mysqli) {
// Rollback if a transaction is open
try { $conn->rollback(); } catch (\Throwable $ignore) {}
}
$_SESSION['error'] = 'Registration failed. ' . $e->getMessage();
header('Location: ../../auth/register.php');
exit;
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!