Restore: Recover src/processors folder accidentally deleted during merge
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 291 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 291 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.4 MiB |
54
src/processors/create_bar_tab.php
Normal file
54
src/processors/create_bar_tab.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Security token validation failed.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if user_id is set in the POST request
|
||||
if (isset($_POST['user_id']) && !empty($_POST['user_id'])) {
|
||||
// Validate user_id as integer
|
||||
$user_id = intval($_POST['user_id']);
|
||||
if ($user_id <= 0) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid user ID.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$created_at = date('Y-m-d H:i:s'); // Use current date and time for created_at
|
||||
|
||||
// First, check if a bar tab already exists for this user_id
|
||||
$stmt = $conn->prepare("SELECT * FROM bar_tabs WHERE user_id = ? LIMIT 1");
|
||||
$stmt->bind_param("i", $user_id);
|
||||
$stmt->execute();
|
||||
$checkResult = $stmt->get_result();
|
||||
|
||||
if ($checkResult->num_rows > 0) {
|
||||
// If a bar tab already exists for this user_id, return an error message
|
||||
echo json_encode(['status' => 'error', 'message' => 'A bar tab already exists for this user.']);
|
||||
} else {
|
||||
// Prepare the SQL query to insert a new record into the bar_tabs table
|
||||
$stmt = $conn->prepare("INSERT INTO bar_tabs (user_id) VALUES (?)");
|
||||
$stmt->bind_param("i", $user_id);
|
||||
|
||||
// Execute the query
|
||||
if ($stmt->execute()) {
|
||||
// If the insertion is successful, return a success message
|
||||
echo json_encode(['status' => 'success', 'message' => 'Bar tab created successfully.']);
|
||||
} else {
|
||||
// If there's an error, return an error message
|
||||
echo json_encode(['status' => 'error', 'message' => 'Error: ' . $conn->error]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If user_id is not provided, return an error message
|
||||
echo json_encode(['status' => 'error', 'message' => 'User ID is required.']);
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
14
src/processors/logout.php
Normal file
14
src/processors/logout.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
|
||||
|
||||
// Destroy the session
|
||||
session_destroy();
|
||||
|
||||
|
||||
|
||||
// Redirect to login page
|
||||
header("Location: index"); // Replace with your actual login page URL
|
||||
exit();
|
||||
?>
|
||||
202
src/processors/process_application.php
Normal file
202
src/processors/process_application.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
$eft_id = strtoupper($user_id." SUBS ".date("Y")." ".getInitialSurname($user_id));
|
||||
$status = 'AWAITING PAYMENT';
|
||||
$description = 'Membership Fees '.date("Y")." ".getInitialSurname($user_id);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
auditLog($user_id, 'CSRF_VALIDATION_FAILED', 'membership_application', null, ['endpoint' => 'process_application.php']);
|
||||
http_response_code(403);
|
||||
die('Security token validation failed. Please try again.');
|
||||
}
|
||||
|
||||
// Get all the form fields with validation
|
||||
$first_name = validateName($_POST['first_name'] ?? '');
|
||||
if ($first_name === false) {
|
||||
die('Invalid first name format.');
|
||||
}
|
||||
|
||||
$last_name = validateName($_POST['last_name'] ?? '');
|
||||
if ($last_name === false) {
|
||||
die('Invalid last name format.');
|
||||
}
|
||||
|
||||
$id_number = validateSAIDNumber($_POST['id_number'] ?? '');
|
||||
if ($id_number === false) {
|
||||
die('Invalid ID number format.');
|
||||
}
|
||||
|
||||
$dob = validateDate($_POST['dob'] ?? '');
|
||||
if ($dob === false) {
|
||||
die('Invalid date of birth format.');
|
||||
}
|
||||
|
||||
$occupation = sanitizeTextInput($_POST['occupation'] ?? '', 100);
|
||||
$tel_cell = validatePhoneNumber($_POST['tel_cell'] ?? '');
|
||||
if ($tel_cell === false) {
|
||||
die('Invalid phone number format.');
|
||||
}
|
||||
|
||||
$email = validateEmail($_POST['email'] ?? '');
|
||||
if ($email === false) {
|
||||
die('Invalid email format.');
|
||||
}
|
||||
|
||||
// Spouse or Partner details (optional)
|
||||
$spouse_first_name = !empty($_POST['spouse_first_name']) ? validateName($_POST['spouse_first_name']) : null;
|
||||
$spouse_last_name = !empty($_POST['spouse_last_name']) ? validateName($_POST['spouse_last_name']) : null;
|
||||
$spouse_id_number = !empty($_POST['spouse_id_number']) ? validateSAIDNumber($_POST['spouse_id_number']) : null;
|
||||
$spouse_dob = !empty($_POST['spouse_dob']) ? validateDate($_POST['spouse_dob']) : NULL;
|
||||
$spouse_occupation = !empty($_POST['spouse_occupation']) ? sanitizeTextInput($_POST['spouse_occupation'], 100) : null;
|
||||
$spouse_tel_cell = !empty($_POST['spouse_tel_cell']) ? validatePhoneNumber($_POST['spouse_tel_cell']) : null;
|
||||
$spouse_email = !empty($_POST['spouse_email']) ? validateEmail($_POST['spouse_email']) : null;
|
||||
|
||||
// Children details (optional)
|
||||
$child_name1 = !empty($_POST['child_name1']) ? $_POST['child_name1'] : null;
|
||||
$child_dob1 = !empty($_POST['child_dob1']) ? $_POST['child_dob1'] : null;
|
||||
$child_name2 = !empty($_POST['child_name2']) ? $_POST['child_name2'] : null;
|
||||
$child_dob2 = !empty($_POST['child_dob2']) ? $_POST['child_dob2'] : null;
|
||||
$child_name3 = !empty($_POST['child_name3']) ? $_POST['child_name3'] : null;
|
||||
$child_dob3 = !empty($_POST['child_dob3']) ? $_POST['child_dob3'] : null;
|
||||
|
||||
// Address and other details
|
||||
$physical_address = $_POST['physical_address'];
|
||||
$postal_address = $_POST['postal_address'];
|
||||
$interests_hobbies = $_POST['interests_hobbies'];
|
||||
|
||||
// Primary vehicle details
|
||||
$vehicle_make = $_POST['vehicle_make'];
|
||||
$vehicle_model = $_POST['vehicle_model'];
|
||||
$vehicle_year = $_POST['vehicle_year'];
|
||||
$vehicle_registration = $_POST['vehicle_registration'];
|
||||
|
||||
// Secondary vehicle details (optional)
|
||||
$secondary_vehicle_make = !empty($_POST['secondary_vehicle_make']) ? $_POST['secondary_vehicle_make'] : null;
|
||||
$secondary_vehicle_model = !empty($_POST['secondary_vehicle_model']) ? $_POST['secondary_vehicle_model'] : null;
|
||||
$secondary_vehicle_year = !empty($_POST['secondary_vehicle_year']) ? $_POST['secondary_vehicle_year'] : null;
|
||||
$secondary_vehicle_registration = !empty($_POST['secondary_vehicle_registration']) ? $_POST['secondary_vehicle_registration'] : null;
|
||||
|
||||
// Start a transaction to ensure data consistency
|
||||
$conn->begin_transaction();
|
||||
|
||||
try {
|
||||
// Insert into the member application table
|
||||
$stmt = $conn->prepare("INSERT INTO membership_application (
|
||||
user_id, first_name, last_name, id_number, dob, occupation, tel_cell, email,
|
||||
spouse_first_name, spouse_last_name, spouse_id_number, spouse_dob, spouse_occupation, spouse_tel_cell, spouse_email,
|
||||
child_name1, child_dob1, child_name2, child_dob2, child_name3, child_dob3,
|
||||
physical_address, postal_address, interests_hobbies, vehicle_make, vehicle_model, vehicle_year, vehicle_registration,
|
||||
secondary_vehicle_make, secondary_vehicle_model, secondary_vehicle_year, secondary_vehicle_registration
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
|
||||
// Check if preparation was successful
|
||||
if (!$stmt) {
|
||||
die("SQL error: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param(
|
||||
"isssssssssssssssssssssssssssssss",
|
||||
$user_id,
|
||||
$first_name,
|
||||
$last_name,
|
||||
$id_number,
|
||||
$dob,
|
||||
$occupation,
|
||||
$tel_cell,
|
||||
$email,
|
||||
$spouse_first_name,
|
||||
$spouse_last_name,
|
||||
$spouse_id_number,
|
||||
$spouse_dob,
|
||||
$spouse_occupation,
|
||||
$spouse_tel_cell,
|
||||
$spouse_email,
|
||||
$child_name1,
|
||||
$child_dob1,
|
||||
$child_name2,
|
||||
$child_dob2,
|
||||
$child_name3,
|
||||
$child_dob3,
|
||||
$physical_address,
|
||||
$postal_address,
|
||||
$interests_hobbies,
|
||||
$vehicle_make,
|
||||
$vehicle_model,
|
||||
$vehicle_year,
|
||||
$vehicle_registration,
|
||||
$secondary_vehicle_make,
|
||||
$secondary_vehicle_model,
|
||||
$secondary_vehicle_year,
|
||||
$secondary_vehicle_registration
|
||||
);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Insert into the membership fees table
|
||||
$payment_amount = calculateProrata(210); // Assuming a fixed membership fee, adjust as needed
|
||||
$payment_date = date('Y-m-d');
|
||||
$membership_start_date = $payment_date;
|
||||
// $membership_end_date = date('Y-12-31');
|
||||
|
||||
// Get today's date
|
||||
$today = new DateTime();
|
||||
|
||||
// Determine the target February
|
||||
if ($today->format('n') > 2) {
|
||||
// If we're past February, target is next year's Feb 28/29
|
||||
$year = $today->format('Y') + 1;
|
||||
} else {
|
||||
// Otherwise, this year's February
|
||||
$year = $today->format('Y');
|
||||
}
|
||||
|
||||
// Handle leap year (Feb 29) automatically
|
||||
$membership_end_date = (new DateTime("$year-02-01"))
|
||||
->modify('last day of this month')
|
||||
->format('Y-m-d');
|
||||
|
||||
$stmt = $conn->prepare("INSERT INTO membership_fees (user_id, payment_amount, payment_date, membership_start_date, membership_end_date, payment_status, payment_id)
|
||||
VALUES (?, ?, ?, ?, ?, 'PENDING', ?)");
|
||||
$stmt->bind_param("idssss", $user_id, $payment_amount, $payment_date, $membership_start_date, $membership_end_date, $eft_id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Commit the transaction
|
||||
$conn->commit();
|
||||
addSubsEFT($eft_id, $user_id, $status, $payment_amount, $description);
|
||||
sendInvoice(getEmail($user_id), getFullName($user_id), $eft_id, formatCurrency($payment_amount), $description);
|
||||
sendAdminNotification('4WDCSA.co.za - New Membership Application - '.$last_name , 'A new member has signed up, '.$first_name.' '.$last_name);
|
||||
header("Location: indemnity");
|
||||
// Success message
|
||||
$response = [
|
||||
'status' => 'success',
|
||||
'message' => 'Your membership application has been submitted successfully!'
|
||||
];
|
||||
} else {
|
||||
throw new Exception("Failed to insert membership fee. SQL error: " . $conn->error);
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Failed to insert member application.SQL error: " . $conn->error);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Rollback the transaction in case of error
|
||||
$conn->rollback();
|
||||
|
||||
// Error response
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'message' => 'Error: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
|
||||
// Return the response in JSON format
|
||||
echo json_encode($response);
|
||||
}
|
||||
?>
|
||||
|
||||
95
src/processors/process_booking.php
Normal file
95
src/processors/process_booking.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
// Start session to retrieve the logged-in user's ID
|
||||
session_start();
|
||||
|
||||
// Get user ID from session (assuming user is logged in)
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
|
||||
// Check if the form has been submitted
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
auditLog($user_id, 'CSRF_VALIDATION_FAILED', 'bookings', null, ['endpoint' => 'process_booking.php']);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Security token validation failed. Please try again.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Validate dates and integers
|
||||
$from_date = validateDate($_POST['from_date'] ?? '');
|
||||
if ($from_date === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid from date format.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$to_date = validateDate($_POST['to_date'] ?? '');
|
||||
if ($to_date === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid to date format.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$num_vehicles = validateInteger($_POST['vehicles'] ?? 0, 1, 10);
|
||||
if ($num_vehicles === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid number of vehicles.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$num_adults = validateInteger($_POST['adults'] ?? 0, 0, 20);
|
||||
if ($num_adults === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid number of adults.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$num_children = validateInteger($_POST['children'] ?? 0, 0, 20);
|
||||
if ($num_children === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid number of children.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get values from the form
|
||||
$add_firewood = isset($_POST['AddExtra']) ? 1 : 0; // Checkbox for extras
|
||||
$is_member = isset($_POST['is_member']) ? (int)$_POST['is_member'] : 0; // Hidden member status
|
||||
$type = "camping";
|
||||
|
||||
// Calculate the total number of nights
|
||||
$date1 = new DateTime($from_date);
|
||||
$date2 = new DateTime($to_date);
|
||||
$nights = $date2->diff($date1)->days;
|
||||
|
||||
// Determine rate per night
|
||||
$rate_per_night = ($is_member) ? 0 : 200; // Free for members, R200 for non-members
|
||||
|
||||
// Calculate the total cost
|
||||
$vehicle_cost = $rate_per_night * $num_vehicles * $nights;
|
||||
$firewood_cost = $add_firewood ? 50 : 0;
|
||||
$total_amount = $vehicle_cost + $firewood_cost;
|
||||
|
||||
// Calculate discount if the user is a member
|
||||
$discount_amount = ($is_member) ? $vehicle_cost : 0;
|
||||
|
||||
// Insert booking into the database
|
||||
$sql = "INSERT INTO bookings (booking_type, user_id, from_date, to_date, num_vehicles, num_adults, num_children, add_firewood, total_amount, discount_amount)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param('sissiiiidd', $type, $user_id, $from_date, $to_date, $num_vehicles, $num_adults, $num_children, $add_firewood, $total_amount, $discount_amount);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Redirect to success page or display success message
|
||||
echo "<script>alert('Booking successfully created!'); window.location.href = 'booking.php';</script>";
|
||||
} else {
|
||||
// Handle error if insert fails
|
||||
echo "<script>alert('Error processing booking. Please try again later.');</script>";
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
} else {
|
||||
echo "Invalid request.";
|
||||
}
|
||||
?>
|
||||
|
||||
146
src/processors/process_camp_booking.php
Normal file
146
src/processors/process_camp_booking.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
// Start session to retrieve the logged-in user's ID
|
||||
session_start();
|
||||
|
||||
// Get user ID from session (assuming user is logged in)
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
|
||||
// Validate user session
|
||||
if (!$user_id) {
|
||||
echo "<script>alert('User is not logged in. Please log in to make a booking.'); window.location.href = 'login.php';</script>";
|
||||
exit();
|
||||
}
|
||||
$is_member = getUserMemberStatus($user_id);
|
||||
|
||||
// Check if the form has been submitted
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
auditLog($user_id, 'CSRF_VALIDATION_FAILED', 'bookings', null, ['endpoint' => 'process_camp_booking.php']);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Security token validation failed. Please try again.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Validate dates and integers
|
||||
$from_date = validateDate($_POST['from_date'] ?? '');
|
||||
if ($from_date === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid from date format.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$to_date = validateDate($_POST['to_date'] ?? '');
|
||||
if ($to_date === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid to date format.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$num_vehicles = validateInteger($_POST['vehicles'] ?? 1, 1, 10);
|
||||
if ($num_vehicles === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid number of vehicles.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$num_adults = validateInteger($_POST['adults'] ?? 0, 0, 20);
|
||||
if ($num_adults === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid number of adults.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$num_children = validateInteger($_POST['children'] ?? 0, 0, 20);
|
||||
if ($num_children === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid number of children.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get values from the form
|
||||
$add_firewood = isset($_POST['AddExtra']) ? 1 : 0; // Checkbox for extras
|
||||
// $is_member = isset($_POST['is_member']) ? (int)$_POST['is_member'] : 0; // Hidden member status
|
||||
$type = "camping";
|
||||
|
||||
// Calculate the total number of nights
|
||||
$date1 = new DateTime($from_date);
|
||||
$date2 = new DateTime($to_date);
|
||||
$nights = $date2->diff($date1)->days;
|
||||
|
||||
// Validate date range
|
||||
if ($nights <= 0) {
|
||||
echo "<script>alert('Invalid date range. Please select valid dates.'); window.history.back();</script>";
|
||||
exit();
|
||||
}
|
||||
|
||||
// Determine rate per night
|
||||
$rate_per_night = 200; // Free for members, R200 for non-members
|
||||
|
||||
// Calculate the total cost
|
||||
$vehicle_cost = $rate_per_night * $num_vehicles * $nights;
|
||||
$total_discount = $is_member ? $vehicle_cost : 0;
|
||||
$firewood_cost = $add_firewood ? 50 : 0;
|
||||
$total_amount = $vehicle_cost + $firewood_cost;
|
||||
$payment_amount = $total_amount - $total_discount;
|
||||
$status = "AWAITING PAYMENT";
|
||||
$description = "BASE4 Camping";
|
||||
|
||||
$payment_id = uniqid();
|
||||
$eft_id = strtoupper($trip_code." ".getLastName($user_id));
|
||||
|
||||
// Insert booking into the database
|
||||
$sql = "INSERT INTO bookings (booking_type, user_id, from_date, to_date, num_vehicles, num_adults, num_children, add_firewood, total_amount, discount_amount, status, payment_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param('sissiiiiddss', $type, $user_id, $from_date, $to_date, $num_vehicles, $num_adults, $num_children, $add_firewood, $total_amount, $total_discount, $status, $payment_id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$booking_id = $conn->insert_id;
|
||||
|
||||
if ($payment_amount < 1) {
|
||||
if (processZeroPayment($payment_id, $payment_amount, $description)) {
|
||||
echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
} else {
|
||||
$error_message = $stmt->error;
|
||||
echo "Error processing booking: $error_message";
|
||||
}
|
||||
} else {
|
||||
addEFT($eft_id, $booking_id, $user_id, $status, $payment_amount, $description);
|
||||
header("Location: payment_confirmation?booking_id=".$booking_id);
|
||||
exit(); // Ensure no further code is executed after the redirect
|
||||
}
|
||||
} else {
|
||||
// Handle error if insert fails and echo the MySQL error
|
||||
$error_message = $stmt->error;
|
||||
echo "Error processing booking: $error_message";
|
||||
}
|
||||
|
||||
// if ($stmt->execute()) {
|
||||
// if ($payment_amount < 1) {
|
||||
// if (processZeroPayment($payment_id, $payment_amount, $description)) {
|
||||
// echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
// } else {
|
||||
// $error_message = $stmt->error;
|
||||
// echo "Error processing booking: $error_message";
|
||||
// }
|
||||
// } else {
|
||||
// if (processPayment($payment_id, $payment_amount, $description)) {
|
||||
// echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
// } else {
|
||||
// $error_message = $stmt->error;
|
||||
// echo "Error processing booking: $error_message";
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // Handle error if insert fails and echo the MySQL error
|
||||
// $error_message = $stmt->error;
|
||||
// echo "Error processing booking: $error_message";
|
||||
// }
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
} else {
|
||||
echo "Invalid request.";
|
||||
}
|
||||
|
||||
145
src/processors/process_course_booking.php
Normal file
145
src/processors/process_course_booking.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
session_start();
|
||||
|
||||
|
||||
// Get user ID from session (assuming user is logged in)
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
|
||||
// Validate user session
|
||||
if (!$user_id) {
|
||||
echo "<script>alert('User is not logged in. Please log in to make a booking.'); window.location.href = 'login.php';</script>";
|
||||
exit();
|
||||
}
|
||||
$is_member = getUserMemberStatus($user_id);
|
||||
$pending_member = getUserMemberStatusPending($user_id);
|
||||
|
||||
// Check if the form has been submitted
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
auditLog($user_id, 'CSRF_VALIDATION_FAILED', 'bookings', null, ['endpoint' => 'process_course_booking.php']);
|
||||
http_response_code(403);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Security token validation failed.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Input variables from the form (use default values if not provided)
|
||||
$additional_members = validateInteger($_POST['members'] ?? 0, 0, 20);
|
||||
if ($additional_members === false) $additional_members = 0;
|
||||
|
||||
$num_adults = validateInteger($_POST['non-members'] ?? 0, 0, 20);
|
||||
if ($num_adults === false) $num_adults = 0;
|
||||
|
||||
$course_id = validateInteger($_POST['course_id'] ?? 0, 1, 999999);
|
||||
if ($course_id === false) {
|
||||
http_response_code(400);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Invalid course ID.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
checkAndRedirectCourseBooking($course_id);
|
||||
// Fetch trip costs from the database
|
||||
$query = "SELECT date, cost_members, cost_nonmembers, course_type FROM courses WHERE course_id = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param('i', $course_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if trip exists
|
||||
if ($result->num_rows === 0) {
|
||||
$response = ['error' => 'Trip not found.'];
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Fetch trip details
|
||||
$course = $result->fetch_assoc();
|
||||
$type = $course['course_type'];
|
||||
$date = $course['date'];
|
||||
$cost_members = intval($course['cost_members']);
|
||||
$cost_nonmembers = intval($course['cost_nonmembers']);
|
||||
|
||||
if ($type === "driver_training") {
|
||||
$description = "Basic 4X4 Driver Training Course " . $date;
|
||||
} elseif ($type === "bush_mechanics") {
|
||||
$description = "Bush Mechanics Course " . $date;
|
||||
} elseif ($type === "rescue_recovery") {
|
||||
$description = "Rescue & Recovery Training Course " . $date;
|
||||
} else {
|
||||
$description = "General Course " . $date; // Default fallback description
|
||||
}
|
||||
|
||||
// Initialize total and discount amount
|
||||
$total = 0;
|
||||
|
||||
// Calculate total based on membership
|
||||
if ($is_member || $pending_member) {
|
||||
$num_members = 1 + $additional_members;
|
||||
$total = ($num_members * $cost_members) + ($num_adults * $cost_nonmembers);
|
||||
$payment_amount = $total;
|
||||
} else {
|
||||
$num_members = 0;
|
||||
$total = (($cost_nonmembers) + ($num_adults * $cost_nonmembers));
|
||||
$payment_amount = $total;
|
||||
$num_adults = $num_adults + 1;
|
||||
}
|
||||
|
||||
$status = "AWAITING PAYMENT";
|
||||
$type = 'course';
|
||||
$payment_id = uniqid();
|
||||
$num_vehicles = 1;
|
||||
$discountAmount = 0;
|
||||
$eft_id = strtoupper("COURSE ".date("m-d", strtotime($date))." ".getInitialSurname($user_id));
|
||||
$notes = "";
|
||||
if ($pending_member){
|
||||
$notes = "Membership Payment pending at time of booking. Please confirm payment has been received.";
|
||||
}
|
||||
|
||||
|
||||
// Insert booking into the database
|
||||
$sql = "INSERT INTO bookings (booking_type, user_id, from_date, to_date, num_vehicles, num_adults, total_amount, discount_amount, status, payment_id, course_id, course_non_members, eft_id, notes)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $conn->prepare($sql);
|
||||
|
||||
if (!$stmt) {
|
||||
die("Preparation failed: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param('sissiiddssiiss', $type, $user_id, $date, $date, $num_vehicles, $num_members, $total, $discountAmount, $status, $payment_id, $course_id, $num_adults, $eft_id, $notes);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$booking_id = $conn->insert_id;
|
||||
|
||||
if ($payment_amount < 1) {
|
||||
if (processZeroPayment($payment_id, $payment_amount, $description)) {
|
||||
echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
} else {
|
||||
$error_message = $stmt->error;
|
||||
echo "Error processing booking: $error_message";
|
||||
}
|
||||
} else {
|
||||
addEFT($eft_id, $booking_id, $user_id, $status, $payment_amount, $description);
|
||||
sendInvoice(getEmail($user_id), getFullName($user_id), $eft_id, formatCurrency($payment_amount), $description);
|
||||
sendAdminNotification('New Course Booking - '.getFullName($user_id), getFullName($user_id).' has booked for '.$description);
|
||||
header("Location: payment_confirmation?token=".encryptData($booking_id, $salt));
|
||||
exit(); // Ensure no further code is executed after the redirect
|
||||
}
|
||||
} else {
|
||||
// Handle error if insert fails and echo the MySQL error
|
||||
$error_message = $stmt->error;
|
||||
echo "Error processing booking: $error_message";
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
} else {
|
||||
echo "Invalid request.";
|
||||
}
|
||||
|
||||
99
src/processors/process_eft.php
Normal file
99
src/processors/process_eft.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
checkAdmin();
|
||||
|
||||
// CSRF Token Validation for POST requests
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
auditLog($_SESSION['user_id'] ?? null, 'CSRF_VALIDATION_FAILED', 'efts', null, ['endpoint' => 'process_eft.php']);
|
||||
http_response_code(403);
|
||||
die('Security token validation failed.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($_GET['token']) || empty($_GET['token'])) {
|
||||
die("Invalid request.");
|
||||
}
|
||||
|
||||
$token = $_GET['token'];
|
||||
// echo $token;
|
||||
$eft_id = decryptData($token, $salt);
|
||||
$user = getUserIdFromEFT($eft_id);
|
||||
|
||||
// echo $eft_id;
|
||||
// Start transaction for atomicity
|
||||
$conn->begin_transaction();
|
||||
|
||||
try {
|
||||
// Update the efts table to set status = 'PAID'
|
||||
$updateEFT = "UPDATE efts SET status = 'PAID' WHERE eft_id = ?";
|
||||
$stmt = $conn->prepare($updateEFT);
|
||||
if (!$stmt) {
|
||||
throw new Exception("Prepare failed: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param("s", $eft_id);
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception("EFT update failed: " . $stmt->error);
|
||||
}
|
||||
$stmt->close();
|
||||
|
||||
// Retrieve the booking_id from efts table
|
||||
$getBooking = "SELECT booking_id FROM efts WHERE eft_id = ?";
|
||||
$stmt = $conn->prepare($getBooking);
|
||||
if (!$stmt) {
|
||||
throw new Exception("Prepare failed: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param("s", $eft_id);
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($booking_id);
|
||||
$stmt->fetch();
|
||||
$stmt->close();
|
||||
|
||||
if (!empty($booking_id)) {
|
||||
// Update the bookings table if booking_id exists
|
||||
$updateBooking = "UPDATE bookings SET status = 'PAID' WHERE booking_id = ?";
|
||||
$stmt = $conn->prepare($updateBooking);
|
||||
if (!$stmt) {
|
||||
throw new Exception("Prepare failed: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param("i", $booking_id);
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception("Booking update failed: " . $stmt->error);
|
||||
}
|
||||
} else {
|
||||
// If no booking_id is found, update membership_fees instead
|
||||
$updateMembership = "UPDATE membership_fees SET payment_status = 'PAID' WHERE payment_id = ?";
|
||||
$stmt = $conn->prepare($updateMembership);
|
||||
if (!$stmt) {
|
||||
throw new Exception("Prepare failed: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param("s", $eft_id);
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception("Membership fee update failed: " . $stmt->error);
|
||||
}
|
||||
}
|
||||
$stmt->close();
|
||||
|
||||
// Commit transaction if everything was successful
|
||||
$conn->commit();
|
||||
sendPaymentConfirmation(getEmail($user), getFullName($user), getEftDescription($eft_id));
|
||||
header("Location: admin_efts");
|
||||
exit(); // Ensure no further code is executed after the redirect
|
||||
} catch (Exception $e) {
|
||||
// Rollback transaction if an error occurs
|
||||
$conn->rollback();
|
||||
echo "Error: " . $e->getMessage();
|
||||
}
|
||||
|
||||
|
||||
// Close database connection
|
||||
$conn->close();
|
||||
|
||||
78
src/processors/process_membership_payment.php
Normal file
78
src/processors/process_membership_payment.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
// Start session to retrieve the logged-in user's ID
|
||||
session_start();
|
||||
|
||||
// Get user ID from session (assuming user is logged in)
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
|
||||
// Validate user session
|
||||
if (!$user_id) {
|
||||
echo "<script>alert('User is not logged in. Please log in to make a booking.'); window.location.href = 'login.php';</script>";
|
||||
exit();
|
||||
}
|
||||
$is_member = getUserMemberStatus($user_id);
|
||||
|
||||
$query = "SELECT payment_amount, payment_status, membership_end_date FROM membership_fees WHERE user_id = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param('i', $user_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if trip exists
|
||||
if ($result->num_rows === 0) {
|
||||
$response = ['error' => 'Application Fee not found.'];
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Fetch trip details
|
||||
$fee = $result->fetch_assoc();
|
||||
$payment_status = $fee['payment_status'];
|
||||
$membership_end_date = $fee['membership_end_date'];
|
||||
$payment_amount = intval($fee['payment_amount']);
|
||||
|
||||
$description = "4WDCSA: Membership Fee " . getFullName($user_id) . " " . date("Y");
|
||||
$payment_id = uniqid();
|
||||
$eft_id = "SUBS 2025 ".getLastName($user_id);
|
||||
|
||||
// Update the membership_fees table to set payment_id
|
||||
$stmt = $conn->prepare("UPDATE membership_fees SET payment_id = ? WHERE user_id = ?");
|
||||
if ($stmt) {
|
||||
$stmt->bind_param("ss", $payment_id, $user_id);
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception("Failed to update membership_fees table.");
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
} else {
|
||||
throw new Exception("Failed to prepare statement for membership_fees table: " . $conn->error);
|
||||
}
|
||||
|
||||
// Get the current date
|
||||
$current_date = new DateTime();
|
||||
|
||||
// Convert $membership_end_date to a DateTime object
|
||||
$membership_end_date_obj = DateTime::createFromFormat('Y-m-d', $membership_end_date);
|
||||
|
||||
// Check if the current date is after membership_end_date
|
||||
// OR if the current date is before or on membership_end_date AND payment_status is "PENDING"
|
||||
if (
|
||||
$current_date > $membership_end_date_obj ||
|
||||
($current_date <= $membership_end_date_obj && $payment_status === "PENDING")
|
||||
) {
|
||||
|
||||
// Call the processMembershipPayment function
|
||||
// processMembershipPayment($payment_id, $payment_amount, $description);
|
||||
addMembershipEFT($eft_id, $user_id, $status, $amount, $description, $membershipfee_id);
|
||||
header("Location: payment_confirmation?booking_id=" . $booking_id);
|
||||
exit(); // Ensure no further code is executed after the redirect
|
||||
}
|
||||
|
||||
152
src/processors/process_payments.php
Normal file
152
src/processors/process_payments.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
checkUserSession();
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
?>
|
||||
<style>
|
||||
.image {
|
||||
width: 400px;
|
||||
/* Set your desired width */
|
||||
height: 350px;
|
||||
/* Set your desired height */
|
||||
overflow: hidden;
|
||||
/* Hide any overflow */
|
||||
display: block;
|
||||
/* Ensure proper block behavior */
|
||||
}
|
||||
|
||||
.image img {
|
||||
width: 100%;
|
||||
/* Image scales to fill the container */
|
||||
height: 100%;
|
||||
/* Image scales to fill the container */
|
||||
object-fit: cover;
|
||||
/* Fills the container while maintaining aspect ratio */
|
||||
object-position: top;
|
||||
/* Aligns the top of the image with the top of the container */
|
||||
display: block;
|
||||
/* Prevents inline whitespace issues */
|
||||
}
|
||||
|
||||
.message-box {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
padding-right: 35px;
|
||||
/* Ensures text doesn't overlap with the close button */
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
/* Centers vertically */
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
<?php
|
||||
$status = "PROCESSING";
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||
if (!empty($bannerImages)) {
|
||||
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||
}
|
||||
?>
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url('<?php echo $randomBanner; ?>');">
|
||||
<div class="banner-overlay"></div>
|
||||
<div class="container">
|
||||
<div class="banner-inner text-white mb-50">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Process Payments</h2>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb justify-content-center mb-20" data-aos="fade-right" data-aos-delay="200" data-aos-duration="1500" data-aos-offset="50">
|
||||
<li class="breadcrumb-item"><a href="index.php">Home</a></li>
|
||||
<li class="breadcrumb-item active">Process Payments</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Tour List Area start -->
|
||||
<section class="tour-list-page py-100 rel z-1">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-12">
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<div class="alert alert-warning message-box">
|
||||
<?php echo $_SESSION['message']; ?>
|
||||
<span class="close-btn" onclick="this.parentElement.style.display='none'">×</span>
|
||||
</div>
|
||||
<?php unset($_SESSION['message']); ?>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
// Query to retrieve data from the bookings table
|
||||
$sql = "SELECT * FROM efts WHERE status = ? ORDER BY timestamp DESC";
|
||||
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param("s", $status);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
// Loop through each row
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$eft_id = $row['eft_id'];
|
||||
$file_name = str_replace(' ', '_', $eft_id);
|
||||
$eft_user = $row['user_id'];
|
||||
$eft_amount = $row['amount'];
|
||||
$eft_description = $row['description'];
|
||||
|
||||
// Output the HTML structure with dynamic data
|
||||
echo '
|
||||
<div class="destination-item style-three bgc-lighter booking " data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="p-4" >
|
||||
<iframe src="uploads/pop/'.$file_name.'.pdf#toolbar=0" width="400px" height="200px"></iframe>
|
||||
<p><a href="uploads/pop/'.$file_name.'.pdf" target="_new" class="theme-btn style-three" style="width:100%;">View Full PDF</a></p>
|
||||
|
||||
</div>
|
||||
<div style="width:100%;" class="content">
|
||||
<h5>' . htmlspecialchars($eft_description) . '</a></h5>
|
||||
<h5>' . getFullName($eft_user) . '</a></h5>
|
||||
<div class="destination-footer">
|
||||
<span class="price"><span>Booking Total: R ' . number_format($eft_amount, 2) . '</span></span>
|
||||
<a href="process_eft.php?token=' . encryptData($eft_id, $salt) . '" class="theme-btn style-three"><span data-hover="POP RECEIVED">PROCESS</span></a>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
} else {
|
||||
echo '<p>There are no pending payments for processing.</p>';
|
||||
}
|
||||
// Close connection
|
||||
$conn->close();
|
||||
?>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Tour List Area end -->
|
||||
|
||||
|
||||
|
||||
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
70
src/processors/process_signature.php
Normal file
70
src/processors/process_signature.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
die(json_encode(['status' => 'error', 'message' => 'User not logged in']));
|
||||
}
|
||||
|
||||
if (isset($_POST['signature'])) {
|
||||
// CSRF Token Validation
|
||||
// if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
// auditLog($_SESSION['user_id'], 'CSRF_VALIDATION_FAILED', 'membership_application', null, ['endpoint' => 'process_signature.php']);
|
||||
// die(json_encode(['status' => 'error', 'message' => 'Security token validation failed']));
|
||||
// }
|
||||
|
||||
$user_id = $_SESSION['user_id']; // Get the user ID from the session
|
||||
$signature = $_POST['signature']; // Base64 image data
|
||||
|
||||
// Decode the base64 image
|
||||
$signature = str_replace('data:image/png;base64,', '', $signature);
|
||||
$signature = str_replace(' ', '+', $signature);
|
||||
$signatureData = base64_decode($signature);
|
||||
|
||||
// Create a file path for the signature image
|
||||
$fileName = 'signature_' . $user_id . '.png';
|
||||
$filePath = 'uploads/signatures/' . $fileName;
|
||||
|
||||
// Ensure the directory exists
|
||||
if (!is_dir('uploads/signatures')) {
|
||||
mkdir('uploads/signatures', 0777, true);
|
||||
}
|
||||
|
||||
// Save the image file
|
||||
if (file_put_contents($filePath, $signatureData)) {
|
||||
// Update the database
|
||||
|
||||
if ($conn->connect_error) {
|
||||
die(json_encode(['status' => 'error', 'message' => 'Database connection failed']));
|
||||
}
|
||||
|
||||
// Update the signature and indemnity acceptance in the membership application table
|
||||
$stmt = $conn->prepare("UPDATE membership_application SET sig = ?, accept_indemnity = 1 WHERE user_id = ?");
|
||||
$stmt->bind_param('si', $filePath, $user_id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Check the payment status
|
||||
$paymentStatus = checkMembershipPaymentStatus($user_id) ? 'PAID' : 'NOT_PAID';
|
||||
|
||||
// Respond with the appropriate redirect URL based on the payment status
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'message' => 'Signature saved successfully!',
|
||||
'paymentStatus' => $paymentStatus // Send payment status
|
||||
]);
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Database update failed']);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to save signature']);
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Signature not provided']);
|
||||
}
|
||||
|
||||
172
src/processors/process_trip_booking.php
Normal file
172
src/processors/process_trip_booking.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
session_start();
|
||||
|
||||
// Get the trip_id from the request (ensure it's sanitized)
|
||||
$trip_id = isset($_POST['trip_id']) ? intval($_POST['trip_id']) : 0;
|
||||
|
||||
checkAndRedirectBooking($trip_id);
|
||||
|
||||
// Check available spaces
|
||||
$available_spaces = getAvailableSpaces($trip_id); // Assuming you're using MySQLi and the function is updated for it
|
||||
|
||||
if ($available_spaces < 1) {
|
||||
// Redirect back to trips.php with an error message
|
||||
header("Location: trips?error=fully_booked");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get user ID from session (assuming user is logged in)
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
|
||||
// Validate user session
|
||||
if (!$user_id) {
|
||||
echo "<script>alert('User is not logged in. Please log in to make a booking.'); window.location.href = 'login.php';</script>";
|
||||
exit();
|
||||
}
|
||||
$is_member = getUserMemberStatus($user_id);
|
||||
|
||||
// Check if the form has been submitted
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
auditLog($user_id, 'CSRF_VALIDATION_FAILED', 'bookings', null, ['endpoint' => 'process_trip_booking.php']);
|
||||
http_response_code(403);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Security token validation failed.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Input variables from the form (use default values if not provided)
|
||||
$num_vehicles = validateInteger($_POST['vehicles'] ?? 1, 1, 10);
|
||||
if ($num_vehicles === false) $num_vehicles = 1;
|
||||
|
||||
$num_adults = validateInteger($_POST['adults'] ?? 1, 1, 20);
|
||||
if ($num_adults === false) $num_adults = 1;
|
||||
|
||||
$num_children = validateInteger($_POST['children'] ?? 0, 0, 20);
|
||||
if ($num_children === false) $num_children = 0;
|
||||
|
||||
$num_pensioners = validateInteger($_POST['pensioners'] ?? 0, 0, 20);
|
||||
if ($num_pensioners === false) $num_pensioners = 0;
|
||||
// Fetch trip costs from the database
|
||||
$query = "SELECT trip_name, cost_members, cost_nonmembers, cost_pensioner_member, cost_pensioner, booking_fee, start_date, end_date, trip_code FROM trips WHERE trip_id = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param('i', $trip_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if trip exists
|
||||
if ($result->num_rows === 0) {
|
||||
$response = ['error' => 'Trip not found.'];
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Fetch trip details
|
||||
$trip = $result->fetch_assoc();
|
||||
$trip_code = $trip['trip_code'];
|
||||
$trip_name = $trip['trip_name'];
|
||||
$cost_members = intval($trip['cost_members']);
|
||||
$cost_nonmembers = intval($trip['cost_nonmembers']);
|
||||
$cost_pensioner_member = intval($trip['cost_pensioner_member']);
|
||||
$cost_pensioner = intval($trip['cost_pensioner']);
|
||||
$member_discount = $cost_nonmembers - $cost_members;
|
||||
$member_discount_pensioner = $cost_pensioner - $cost_pensioner_member;
|
||||
$booking_fee = $trip['booking_fee'];
|
||||
$radioCost = $radio ? 50 : 0;
|
||||
$start_date = $trip['start_date']; // Start date of the trip
|
||||
$end_date = $trip['end_date']; // End date of the trip
|
||||
|
||||
|
||||
// Assume the membership status is determined elsewhere
|
||||
$is_member = getUserMemberStatus($user_id);
|
||||
|
||||
// Initialize total and discount amount
|
||||
$total = 0;
|
||||
$discountAmount = 0;
|
||||
|
||||
// Calculate total based on membership
|
||||
if ($is_member) {
|
||||
$total = (($num_adults + $num_children) * $cost_nonmembers) + ($num_pensioners * $cost_pensioner) + $radioCost + ($num_vehicles * $booking_fee);
|
||||
$discountAmount = (($num_adults + $num_children) * $member_discount) + ($num_pensioners * $member_discount_pensioner );
|
||||
$payment_amount = $total - $discountAmount;
|
||||
} else {
|
||||
$total = (($num_adults + $num_children) * $cost_nonmembers) + ($num_pensioners * $cost_pensioner) + $radioCost + ($num_vehicles * $booking_fee);
|
||||
$payment_amount = $total;
|
||||
}
|
||||
|
||||
$status = "AWAITING PAYMENT";
|
||||
$description = $trip_name;
|
||||
$type = 'trip';
|
||||
$payment_id = uniqid();
|
||||
// $eft_id = strtoupper(base_convert(time(), 10, 36)); // Convert timestamp to base36
|
||||
$eft_id = strtoupper($trip_code." ".getInitialSurname($user_id));
|
||||
|
||||
|
||||
// Insert booking into the database
|
||||
$sql = "INSERT INTO bookings (booking_type, user_id, from_date, to_date, num_vehicles, num_adults, num_children, total_amount, discount_amount, status, payment_id, trip_id, radio, eft_id, num_pensioners)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $conn->prepare($sql);
|
||||
|
||||
if (!$stmt) {
|
||||
die("Preparation failed: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param('sissiiiddssiisi', $type, $user_id, $start_date, $end_date, $num_vehicles, $num_adults, $num_children, $total, $discountAmount, $status, $payment_id, $trip_id, $radio, $eft_id, $num_pensioners);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Get the generated booking_id
|
||||
$booking_id = $conn->insert_id;
|
||||
|
||||
if ($payment_amount < 1) {
|
||||
if (processZeroPayment($payment_id, $payment_amount, $description)) {
|
||||
echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
} else {
|
||||
$error_message = $stmt->error;
|
||||
echo "Error processing booking: $error_message";
|
||||
}
|
||||
} else {
|
||||
addEFT($eft_id, $booking_id, $user_id, $status, $payment_amount, $description);
|
||||
sendAdminNotification('New Trip Booking - '.getFullName($user_id), getFullName($user_id).' has booked for '.$description);
|
||||
header("Location: payment_confirmation?token=".encryptData($booking_id, $salt));
|
||||
exit(); // Ensure no further code is executed after the redirect
|
||||
}
|
||||
} else {
|
||||
// Handle error if insert fails and echo the MySQL error
|
||||
$error_message = $stmt->error;
|
||||
echo "Error processing booking: $error_message";
|
||||
}
|
||||
|
||||
// if ($stmt->execute()) {
|
||||
// if ($payment_amount < 1) {
|
||||
// if (processZeroPayment($payment_id, $payment_amount, $description)) {
|
||||
// echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
// } else {
|
||||
// $error_message = $stmt->error;
|
||||
// echo "Error processing booking: $error_message";
|
||||
// }
|
||||
// } else {
|
||||
// if (processPayment($payment_id, $payment_amount, $description)) {
|
||||
// echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
// } else {
|
||||
// $error_message = $stmt->error;
|
||||
// echo "Error processing booking: $error_message";
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // Handle error if insert fails and echo the MySQL error
|
||||
// $error_message = $stmt->error;
|
||||
// echo "Error processing booking: $error_message";
|
||||
// }
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
} else {
|
||||
echo "Invalid request.";
|
||||
}
|
||||
|
||||
147
src/processors/register_user.php
Normal file
147
src/processors/register_user.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
require_once($rootPath . "/vendor/autoload.php");
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
// Create connection
|
||||
$conn = openDatabaseConnection();
|
||||
|
||||
// Check connection
|
||||
if ($conn->connect_error) {
|
||||
die("Connection failed: " . $conn->connect_error);
|
||||
}
|
||||
|
||||
|
||||
// Form processing
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
auditLog(null, 'CSRF_VALIDATION_FAILED', 'users', null, ['endpoint' => 'register_user.php']);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Security token validation failed. Please try again.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check rate limiting on registration endpoint (by IP)
|
||||
$ip = getClientIPAddress();
|
||||
$cutoffTime = date('Y-m-d H:i:s', time() - (3600)); // Last hour
|
||||
|
||||
$stmt = $conn->prepare("SELECT COUNT(*) as count FROM audit_log WHERE action = 'REGISTRATION_ATTEMPT' AND ip_address = ? AND created_at > ?");
|
||||
$stmt->bind_param('ss', $ip, $cutoffTime);
|
||||
$stmt->execute();
|
||||
$stmt->bind_result($regAttempts);
|
||||
$stmt->fetch();
|
||||
$stmt->close();
|
||||
|
||||
// Allow max 5 registration attempts per IP per hour
|
||||
if ($regAttempts >= 5) {
|
||||
auditLog(null, 'REGISTRATION_RATE_LIMIT_EXCEEDED', 'users', null, ['ip' => $ip, 'attempts' => $regAttempts]);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Too many registration attempts. Please try again later.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Validate and sanitize first name
|
||||
$first_name = validateName($_POST['first_name'] ?? '');
|
||||
if ($first_name === false) {
|
||||
auditLog(null, 'REGISTRATION_INVALID_FIRST_NAME', 'users');
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid first name. Only letters, spaces, hyphens, and apostrophes allowed (2-100 characters).']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Validate and sanitize last name
|
||||
$last_name = validateName($_POST['last_name'] ?? '');
|
||||
if ($last_name === false) {
|
||||
auditLog(null, 'REGISTRATION_INVALID_LAST_NAME', 'users');
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid last name. Only letters, spaces, hyphens, and apostrophes allowed (2-100 characters).']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Validate and sanitize phone number
|
||||
$phone_number = validatePhoneNumber($_POST['phone_number'] ?? '');
|
||||
if ($phone_number === false) {
|
||||
auditLog(null, 'REGISTRATION_INVALID_PHONE', 'users');
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid phone number format.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Validate email
|
||||
$email = validateEmail($_POST['email'] ?? '');
|
||||
if ($email === false) {
|
||||
auditLog(null, 'REGISTRATION_INVALID_EMAIL', 'users');
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid email format.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$password = $_POST['password'] ?? '';
|
||||
$password_confirm = $_POST['password_confirm'] ?? '';
|
||||
|
||||
// Validate password strength (minimum 8 characters, must contain uppercase, lowercase, number, special char)
|
||||
if (strlen($password) < 8) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Password must be at least 8 characters long.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!preg_match('/[A-Z]/', $password) || !preg_match('/[a-z]/', $password) ||
|
||||
!preg_match('/[0-9]/', $password) || !preg_match('/[!@#$%^&*]/', $password)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Password must contain uppercase, lowercase, number, and special character (!@#$%^&*).']);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($password !== $password_confirm) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Passwords do not match.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if the email is already registered
|
||||
$stmt = $conn->prepare('SELECT user_id FROM users WHERE email = ?');
|
||||
$stmt->bind_param('s', $email);
|
||||
$stmt->execute();
|
||||
$stmt->store_result();
|
||||
|
||||
if ($stmt->num_rows > 0) {
|
||||
auditLog(null, 'REGISTRATION_EMAIL_EXISTS', 'users', null, ['email' => $email]);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Email is already registered.']);
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
exit();
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
|
||||
// Hash password
|
||||
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
|
||||
|
||||
// Generate email verification token
|
||||
$token = bin2hex(random_bytes(50));
|
||||
|
||||
// Prepare and execute query
|
||||
$stmt = $conn->prepare('INSERT INTO users (first_name, last_name, phone_number, email, password, token, is_verified, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
|
||||
$is_verified = 0; // Not verified
|
||||
$type = 'credentials';
|
||||
$stmt->bind_param('ssssssis', $first_name, $last_name, $phone_number, $email, $hashed_password, $token, $is_verified, $type);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$newUser_id = $conn->insert_id;
|
||||
processLegacyMembership($newUser_id);
|
||||
auditLog($newUser_id, 'USER_REGISTRATION', 'users', $newUser_id, ['email' => $email]);
|
||||
|
||||
if (sendVerificationEmail($email, $first_name . ' ' . $last_name, $token)) {
|
||||
sendEmail($_ENV['ADMIN_EMAIL'], '4WDCSA: New User Registration', $first_name . ' ' . $last_name . ' (' . $email . ') has just created an account using Credentials.');
|
||||
echo json_encode(['status' => 'success', 'message' => 'Registration successful. Please check your email to verify your account.']);
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to send verification email.']);
|
||||
}
|
||||
} else {
|
||||
auditLog(null, 'REGISTRATION_DATABASE_ERROR', 'users', null, ['email' => $email]);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to register user.']);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
$conn->close();
|
||||
|
||||
49
src/processors/send_reset_link.php
Normal file
49
src/processors/send_reset_link.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
$response = array('status' => 'error', 'message' => 'Something went wrong');
|
||||
|
||||
if (isset($_POST['email'])) {
|
||||
$email = $_POST['email'];
|
||||
|
||||
// Check if the email exists
|
||||
$sql = "SELECT user_id FROM users WHERE email = ?";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param("s", $email);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
$user = $result->fetch_assoc();
|
||||
$user_id = $user['user_id'];
|
||||
|
||||
// Generate a unique token
|
||||
$token = bin2hex(random_bytes(50));
|
||||
|
||||
// Store the token and expiration time in the database
|
||||
$expiry = date("Y-m-d H:i:s", strtotime('+3 hour')); // Token expires in 1 hour
|
||||
$sql = "INSERT INTO password_resets (user_id, token, expires_at) VALUES (?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE token = VALUES(token), expires_at = VALUES(expires_at)";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param("iss", $user_id, $token, $expiry);
|
||||
$stmt->execute();
|
||||
|
||||
// Send the reset link to the user
|
||||
$reset_link = "https://www.4wdcsa.co.za/reset_password.php?token=$token";
|
||||
$subject = "Password Reset Request";
|
||||
$message = "Click the following link to reset your password: $reset_link";
|
||||
sendEmail($email, $subject, $message);
|
||||
|
||||
$response['status'] = 'success';
|
||||
$response['message'] = 'Password reset link has been sent to your email.';
|
||||
} else {
|
||||
$response['message'] = 'Email not found.';
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
?>
|
||||
|
||||
48
src/processors/submit_order.php
Normal file
48
src/processors/submit_order.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
session_start();
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Security token validation failed.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
if (isset($_POST['tab_id']) && isset($_SESSION['cart'][$_POST['tab_id']])) {
|
||||
$tab_id = (int) $_POST['tab_id']; // Ensure it's an integer
|
||||
$drinks = $_SESSION['cart'][$tab_id];
|
||||
$created_at = date('Y-m-d H:i:s');
|
||||
|
||||
$errors = []; // Array to store SQL errors
|
||||
|
||||
foreach ($drinks as $drink) {
|
||||
$drink_id = (int) $drink['item_id']; // Ensure drink ID is an integer
|
||||
$drink_name = $drink['item_name']; // No escaping needed with prepared statements
|
||||
$drink_price = (float) $drink['item_price']; // Ensure price is a float
|
||||
$user_id = (int) $drink['user_id']; // Convert to integer
|
||||
|
||||
// Insert each drink into the bar_transactions table using prepared statement
|
||||
$stmt = $conn->prepare("INSERT INTO bar_transactions (user_id, tab_id, item_id, item_name, item_price) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->bind_param("iiisi", $user_id, $tab_id, $drink_id, $drink_name, $drink_price);
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
$errors[] = "Error inserting drink ID $drink_id: " . $conn->error;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
// Clear the cart for this tab after successful submission
|
||||
unset($_SESSION['cart'][$tab_id]);
|
||||
echo json_encode(['status' => 'success', 'message' => 'Order submitted successfully!']);
|
||||
} else {
|
||||
// Log all errors and return failure message
|
||||
error_log(implode("\n", $errors)); // Log errors to the server
|
||||
echo json_encode(['status' => 'error', 'message' => 'Some items failed to be added.', 'errors' => $errors]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Cart is empty or tab ID is invalid.']);
|
||||
}
|
||||
|
||||
215
src/processors/submit_pop.php
Normal file
215
src/processors/submit_pop.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
$headerStyle = 'light';
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
checkUserSession();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
|
||||
if (!$user_id) {
|
||||
die("Not logged in.");
|
||||
}
|
||||
|
||||
// Handle POST submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
http_response_code(403);
|
||||
die('Security token validation failed. Please try again.');
|
||||
}
|
||||
|
||||
$eft_id = $_POST['eft_id'] ?? null;
|
||||
|
||||
if (!$eft_id || !isset($_FILES['pop_file'])) {
|
||||
echo "<div class='alert alert-danger'>Invalid submission: missing eft_id or file.</div>";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Validate file using hardened validation function
|
||||
$validationResult = validateFileUpload($_FILES['pop_file'], 'proof_of_payment');
|
||||
|
||||
if ($validationResult === false) {
|
||||
echo "<div class='alert alert-danger'>Invalid file. Only PDF files under 10MB are allowed.</div>";
|
||||
exit;
|
||||
}
|
||||
|
||||
$target_dir = "uploads/pop/";
|
||||
$randomFilename = $validationResult['filename'];
|
||||
$target_file = $target_dir . $randomFilename;
|
||||
|
||||
// Make sure target directory exists and writable
|
||||
if (!is_dir($target_dir)) {
|
||||
mkdir($target_dir, 0755, true);
|
||||
}
|
||||
|
||||
if (!is_writable($target_dir)) {
|
||||
echo "<div class='alert alert-danger'>Upload directory is not writable: $target_dir</div>";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (move_uploaded_file($_FILES['pop_file']['tmp_name'], $target_file)) {
|
||||
chmod($target_file, 0644);
|
||||
|
||||
// Update EFT and booking status
|
||||
$payment_type = $_POST['payment_type'] ?? 'booking';
|
||||
|
||||
if ($payment_type === 'membership') {
|
||||
// Update EFT and booking status
|
||||
$stmt1 = $conn->prepare("UPDATE efts SET status = 'PROCESSING' WHERE eft_id = ?");
|
||||
$stmt1->bind_param("s", $eft_id);
|
||||
$stmt1->execute();
|
||||
$stmt1->close();
|
||||
|
||||
// Update membership fee status
|
||||
$stmt = $conn->prepare("UPDATE membership_fees SET payment_status = 'PROCESSING' WHERE payment_id = ?");
|
||||
$stmt->bind_param("s", $eft_id);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
} else {
|
||||
// Update EFT and booking status
|
||||
$stmt1 = $conn->prepare("UPDATE efts SET status = 'PROCESSING' WHERE eft_id = ?");
|
||||
$stmt1->bind_param("s", $eft_id);
|
||||
$stmt1->execute();
|
||||
$stmt1->close();
|
||||
|
||||
$stmt2 = $conn->prepare("UPDATE bookings SET status = 'PROCESSING' WHERE eft_id = ?");
|
||||
$stmt2->bind_param("s", $eft_id);
|
||||
$stmt2->execute();
|
||||
$stmt2->close();
|
||||
}
|
||||
|
||||
// Send notification email using sendPOP()
|
||||
$fullname = getFullName($user_id);
|
||||
$eftDetails = getEFTDetails($eft_id);
|
||||
|
||||
if ($eftDetails) {
|
||||
$amount = "R" . number_format($eftDetails['amount'], 2);
|
||||
$description = $eftDetails['description'];
|
||||
} else {
|
||||
$amount = "R0.00";
|
||||
$description = "Payment";
|
||||
}
|
||||
|
||||
if (sendPOP($fullname, $randomFilename, $amount, $description)) {
|
||||
$_SESSION['message'] = "Thank you! Your payment proof has been uploaded and notification sent.";
|
||||
} else {
|
||||
$_SESSION['message'] = "Payment uploaded, but notification email could not be sent.";
|
||||
}
|
||||
|
||||
// Log the action
|
||||
auditLog($user_id, 'POP_UPLOAD', 'efts', $eft_id, ['filename' => $randomFilename, 'payment_type' => $payment_type]);
|
||||
|
||||
header("Location: bookings");
|
||||
exit;
|
||||
|
||||
} else {
|
||||
echo "<div class='alert alert-danger'>Unable to move uploaded file.</div>";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Fetch bookings for dropdown
|
||||
$stmt = $conn->prepare("
|
||||
SELECT eft_id AS id, 'booking' AS type FROM bookings WHERE user_id = ? AND status = 'AWAITING PAYMENT'
|
||||
UNION
|
||||
SELECT payment_id AS id, 'membership' AS type FROM membership_fees WHERE user_id = ? AND payment_status = 'PENDING'
|
||||
");
|
||||
$stmt->bind_param("ii", $user_id, $user_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$items = $result->fetch_all(MYSQLI_ASSOC);
|
||||
|
||||
|
||||
|
||||
|
||||
$bannerFolder = 'assets/images/banners/';
|
||||
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
|
||||
|
||||
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
|
||||
if (!empty($bannerImages)) {
|
||||
$randomBanner = $bannerImages[array_rand($bannerImages)];
|
||||
}
|
||||
?>
|
||||
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url('<?php echo $randomBanner; ?>');">
|
||||
<div class="banner-overlay"></div>
|
||||
<div class="container">
|
||||
<div class="banner-inner text-white mb-50">
|
||||
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">Submit Proof of Payment</h2>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb justify-content-center mb-20" data-aos="fade-right" data-aos-delay="200" data-aos-duration="1500" data-aos-offset="50">
|
||||
<li class="breadcrumb-item"><a href="index">Home</a></li>
|
||||
<li class="breadcrumb-item active">Submit Proof of Payment</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Tour List Area start -->
|
||||
<section class="tour-list-page py-100 rel z-1">
|
||||
<div class="container" style="max-width:600px;">
|
||||
<div class="row">
|
||||
<div class="comment-form bgc-lighter z-1 rel mb-30 rmb-55" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="widget widget-booking" data-aos="fade-up" data-aos-duration="1500" data-aos-offset="50">
|
||||
<div class="section-title">
|
||||
<h3>Submit Proof of Payment</h3>
|
||||
<div style="text-align: center;" id="responseMessage"></div>
|
||||
<p>To finalise your booking/membership, select the payment reference below, and then upload your PDF proof of payment.</p> <!-- Message display area -->
|
||||
</div>
|
||||
<?php if (count($items) > 0) {?>
|
||||
|
||||
<form enctype="multipart/form-data" method="POST">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
|
||||
<div class="row mt-35">
|
||||
<ul class="tickets clearfix">
|
||||
<li>
|
||||
Select Payment Reference:
|
||||
<select name="eft_id" id="eft_id" required onchange="updatePaymentType(this)">
|
||||
<?php
|
||||
if (count($items) > 0) {
|
||||
foreach ($items as $item) {
|
||||
$label = strtoupper($item['type']) . ' - ' . htmlspecialchars($item['id']);
|
||||
echo '<option value="' . htmlspecialchars($item['id']) . '" data-type="' . $item['type'] . '">' . $label . '</option>';
|
||||
}
|
||||
} else {
|
||||
echo '<option value="" disabled selected>No payments available</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<input type="hidden" name="payment_type" id="payment_type">
|
||||
</li>
|
||||
</ul>
|
||||
<li>
|
||||
<input style="border-radius:30px;" type="file" name="pop_file" id="pop_file" accept="application/pdf" class="form-control" required>
|
||||
</li>
|
||||
</div>
|
||||
<div class="mt-10 mb-0">
|
||||
<button type="submit" class="theme-btn style-two" style="width:100%;">Submit POP</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<?php
|
||||
}else{
|
||||
echo 'No unpaid bookings';
|
||||
}?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function updatePaymentType(selectEl) {
|
||||
const selectedOption = selectEl.options[selectEl.selectedIndex];
|
||||
const type = selectedOption.getAttribute('data-type');
|
||||
document.getElementById('payment_type').value = type;
|
||||
}
|
||||
window.onload = function() {
|
||||
const dropdown = document.getElementById('eft_id');
|
||||
updatePaymentType(dropdown); // set default value on page load
|
||||
};
|
||||
</script>
|
||||
|
||||
<?php include_once($rootPath . '/components/insta_footer.php'); ?>
|
||||
129
src/processors/update_application.php
Normal file
129
src/processors/update_application.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
$user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
|
||||
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// Get all the form fields
|
||||
$first_name = $_POST['first_name'];
|
||||
$last_name = $_POST['last_name'];
|
||||
$id_number = $_POST['id_number'];
|
||||
$dob = $_POST['dob'];
|
||||
$occupation = $_POST['occupation'];
|
||||
$tel_cell = $_POST['tel_cell'];
|
||||
$email = $_POST['email'];
|
||||
|
||||
// Spouse or Partner details (optional)
|
||||
$spouse_first_name = !empty($_POST['spouse_first_name']) ? $_POST['spouse_first_name'] : null;
|
||||
$spouse_last_name = !empty($_POST['spouse_last_name']) ? $_POST['spouse_last_name'] : null;
|
||||
$spouse_id_number = !empty($_POST['spouse_id_number']) ? $_POST['spouse_id_number'] : null;
|
||||
$spouse_dob = !empty($_POST['spouse_dob']) ? $_POST['spouse_dob'] : NULL; // if empty, set to NULL
|
||||
$spouse_occupation = !empty($_POST['spouse_occupation']) ? $_POST['spouse_occupation'] : null;
|
||||
$spouse_tel_cell = !empty($_POST['spouse_tel_cell']) ? $_POST['spouse_tel_cell'] : null;
|
||||
$spouse_email = !empty($_POST['spouse_email']) ? $_POST['spouse_email'] : null;
|
||||
|
||||
// Children details (optional)
|
||||
$child_name1 = !empty($_POST['child_name1']) ? $_POST['child_name1'] : null;
|
||||
$child_dob1 = !empty($_POST['child_dob1']) ? $_POST['child_dob1'] : null;
|
||||
$child_name2 = !empty($_POST['child_name2']) ? $_POST['child_name2'] : null;
|
||||
$child_dob2 = !empty($_POST['child_dob2']) ? $_POST['child_dob2'] : null;
|
||||
$child_name3 = !empty($_POST['child_name3']) ? $_POST['child_name3'] : null;
|
||||
$child_dob3 = !empty($_POST['child_dob3']) ? $_POST['child_dob3'] : null;
|
||||
|
||||
// Address and other details
|
||||
$physical_address = $_POST['physical_address'];
|
||||
$postal_address = $_POST['postal_address'];
|
||||
$interests_hobbies = $_POST['interests_hobbies'];
|
||||
|
||||
// Primary vehicle details
|
||||
$vehicle_make = $_POST['vehicle_make'];
|
||||
$vehicle_model = $_POST['vehicle_model'];
|
||||
$vehicle_year = $_POST['vehicle_year'];
|
||||
$vehicle_registration = $_POST['vehicle_registration'];
|
||||
|
||||
// Secondary vehicle details (optional)
|
||||
$secondary_vehicle_make = !empty($_POST['secondary_vehicle_make']) ? $_POST['secondary_vehicle_make'] : null;
|
||||
$secondary_vehicle_model = !empty($_POST['secondary_vehicle_model']) ? $_POST['secondary_vehicle_model'] : null;
|
||||
$secondary_vehicle_year = !empty($_POST['secondary_vehicle_year']) ? $_POST['secondary_vehicle_year'] : null;
|
||||
$secondary_vehicle_registration = !empty($_POST['secondary_vehicle_registration']) ? $_POST['secondary_vehicle_registration'] : null;
|
||||
|
||||
// Start a transaction to ensure data consistency
|
||||
$conn->begin_transaction();
|
||||
|
||||
try {
|
||||
// Prepare the SQL update statement
|
||||
$stmt = $conn->prepare("UPDATE membership_application SET
|
||||
first_name = ?, last_name = ?, id_number = ?, dob = ?, occupation = ?, tel_cell = ?, email = ?,
|
||||
spouse_first_name = ?, spouse_last_name = ?, spouse_id_number = ?, spouse_dob = ?, spouse_occupation = ?, spouse_tel_cell = ?, spouse_email = ?,
|
||||
child_name1 = ?, child_dob1 = ?, child_name2 = ?, child_dob2 = ?, child_name3 = ?, child_dob3 = ?,
|
||||
physical_address = ?, postal_address = ?, interests_hobbies = ?, vehicle_make = ?, vehicle_model = ?, vehicle_year = ?, vehicle_registration = ?,
|
||||
secondary_vehicle_make = ?, secondary_vehicle_model = ?, secondary_vehicle_year = ?, secondary_vehicle_registration = ?
|
||||
WHERE user_id = ?");
|
||||
|
||||
// Check if preparation was successful
|
||||
if (!$stmt) {
|
||||
die("SQL error: " . $conn->error);
|
||||
}
|
||||
|
||||
$stmt->bind_param(
|
||||
"sssssssssssssssssssssssssssssssi",
|
||||
$first_name,
|
||||
$last_name,
|
||||
$id_number,
|
||||
$dob,
|
||||
$occupation,
|
||||
$tel_cell,
|
||||
$email,
|
||||
$spouse_first_name,
|
||||
$spouse_last_name,
|
||||
$spouse_id_number,
|
||||
$spouse_dob,
|
||||
$spouse_occupation,
|
||||
$spouse_tel_cell,
|
||||
$spouse_email,
|
||||
$child_name1,
|
||||
$child_dob1,
|
||||
$child_name2,
|
||||
$child_dob2,
|
||||
$child_name3,
|
||||
$child_dob3,
|
||||
$physical_address,
|
||||
$postal_address,
|
||||
$interests_hobbies,
|
||||
$vehicle_make,
|
||||
$vehicle_model,
|
||||
$vehicle_year,
|
||||
$vehicle_registration,
|
||||
$secondary_vehicle_make,
|
||||
$secondary_vehicle_model,
|
||||
$secondary_vehicle_year,
|
||||
$secondary_vehicle_registration,
|
||||
$user_id // User ID for WHERE condition
|
||||
);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$conn->commit();
|
||||
header("Location: membership_details");
|
||||
exit(); // Ensure no further code is executed after the redirect
|
||||
} else {
|
||||
throw new Exception("Failed to update member application. SQL error: " . $conn->error);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Rollback the transaction in case of error
|
||||
$conn->rollback();
|
||||
|
||||
// Error response
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'message' => 'Error: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
42
src/processors/update_user.php
Normal file
42
src/processors/update_user.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
|
||||
$response = array('status' => 'error', 'message' => 'Something went wrong');
|
||||
|
||||
// Check if the user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
$response['message'] = 'You are not logged in.';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
// Handle updating user details (excluding profile picture)
|
||||
if (isset($_POST['first_name'], $_POST['last_name'], $_POST['phone_number'], $_POST['email'])) {
|
||||
$first_name = ucwords(strtolower($_POST['first_name']));
|
||||
$last_name = ucwords(strtolower($_POST['last_name']));
|
||||
$phone_number = $_POST['phone_number'];
|
||||
$email = $_POST['email'];
|
||||
|
||||
// Update user details in the database
|
||||
$sql = "UPDATE users SET first_name = ?, last_name = ?, phone_number = ?, email = ? WHERE user_id = ?";
|
||||
$stmt = $conn->prepare($sql);
|
||||
$stmt->bind_param("ssssi", $first_name, $last_name, $phone_number, $email, $user_id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
$response['status'] = 'success';
|
||||
$response['message'] = 'User details updated successfully';
|
||||
} else {
|
||||
$response['message'] = 'Failed to update user details';
|
||||
}
|
||||
} else {
|
||||
$response['message'] = 'Invalid form submission';
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
|
||||
81
src/processors/upload_profile_picture.php
Normal file
81
src/processors/upload_profile_picture.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
session_start();
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/src/config/connection.php');
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
|
||||
$response = array('status' => 'error', 'message' => 'Something went wrong');
|
||||
|
||||
// Check if the user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
$response['message'] = 'You are not logged in.';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
// Handle profile picture upload
|
||||
if (isset($_FILES['profile_picture']) && $_FILES['profile_picture']['error'] != UPLOAD_ERR_NO_FILE) {
|
||||
// Validate file using hardened validation function
|
||||
$validationResult = validateFileUpload($_FILES['profile_picture'], 'profile_picture');
|
||||
|
||||
if ($validationResult === false) {
|
||||
$response['message'] = 'Invalid file. Only JPG, JPEG, PNG, GIF, and WEBP images under 5MB are allowed.';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Extract validated filename
|
||||
$randomFilename = $validationResult['filename'];
|
||||
$target_dir = "assets/images/pp/";
|
||||
$target_file = $target_dir . $randomFilename;
|
||||
|
||||
// Ensure upload directory exists and is writable
|
||||
if (!is_dir($target_dir)) {
|
||||
mkdir($target_dir, 0755, true);
|
||||
}
|
||||
|
||||
if (!is_writable($target_dir)) {
|
||||
$response['message'] = 'Upload directory is not writable.';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Move the uploaded file
|
||||
if (move_uploaded_file($_FILES['profile_picture']['tmp_name'], $target_file)) {
|
||||
// Set secure file permissions (readable but not executable)
|
||||
chmod($target_file, 0644);
|
||||
|
||||
// Update the profile picture path in the database
|
||||
$sql = "UPDATE users SET profile_pic = ? WHERE user_id = ?";
|
||||
$stmt = $conn->prepare($sql);
|
||||
if (!$stmt) {
|
||||
$response['message'] = 'Database error.';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
$stmt->bind_param("si", $target_file, $user_id);
|
||||
if ($stmt->execute()) {
|
||||
$_SESSION['profile_pic'] = $target_file;
|
||||
$response['status'] = 'success';
|
||||
$response['message'] = 'Profile picture updated successfully';
|
||||
|
||||
// Log the action
|
||||
auditLog($user_id, 'PROFILE_PIC_UPLOAD', 'users', $user_id, ['filename' => $randomFilename]);
|
||||
} else {
|
||||
$response['message'] = 'Failed to update profile picture in the database';
|
||||
}
|
||||
$stmt->close();
|
||||
} else {
|
||||
$response['message'] = 'Failed to move uploaded file.';
|
||||
}
|
||||
} else {
|
||||
$response['message'] = 'No file uploaded or file error.';
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
?>
|
||||
|
||||
BIN
src/processors/uploads/pop/c97bc77d8901921ed82978c4ed68ec95.pdf
Normal file
BIN
src/processors/uploads/pop/c97bc77d8901921ed82978c4ed68ec95.pdf
Normal file
Binary file not shown.
BIN
src/processors/uploads/signatures/signature_155.png
Normal file
BIN
src/processors/uploads/signatures/signature_155.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
223
src/processors/validate_login.php
Normal file
223
src/processors/validate_login.php
Normal file
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . "/src/config/session.php");
|
||||
require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
require_once($rootPath . '/google-client/vendor/autoload.php'); // Add this line for Google Client
|
||||
|
||||
// Check if connection is established
|
||||
if (!$conn) {
|
||||
json_encode(['status' => 'error', 'message' => 'Database connection failed.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Google Client Setup
|
||||
$client = new Google_Client();
|
||||
$client->setClientId($_ENV['GOOGLE_CLIENT_ID']);
|
||||
$client->setClientSecret($_ENV['GOOGLE_CLIENT_SECRET']);
|
||||
$client->setRedirectUri($_ENV['HOST'] . '/validate_login');
|
||||
$client->addScope("email");
|
||||
$client->addScope("profile");
|
||||
// 👇 Add this to force the account picker
|
||||
$client->setPrompt('select_account');
|
||||
|
||||
// Check if Google login code is set
|
||||
if (isset($_GET['code'])) {
|
||||
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
|
||||
if (!isset($token["error"])) {
|
||||
$client->setAccessToken($token['access_token']);
|
||||
$google_oauth = new Google_Service_Oauth2($client);
|
||||
$google_account_info = $google_oauth->userinfo->get();
|
||||
|
||||
// Get user info from Google
|
||||
$email = $google_account_info->email;
|
||||
$name = $google_account_info->name;
|
||||
$first_name = $google_account_info->given_name;
|
||||
$last_name = $google_account_info->family_name;
|
||||
$picture = $google_account_info->picture;
|
||||
|
||||
// Check if the user exists in the database
|
||||
$query = "SELECT * FROM users WHERE email = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bind_param("s", $email);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows == 0) {
|
||||
// User does not exist, so register them
|
||||
$password = null; // No password for Google login
|
||||
$query = "INSERT INTO users (email, first_name, last_name, profile_pic, password, is_verified) VALUES (?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $conn->prepare($query);
|
||||
$is_verified = 1; // Assuming Google users are considered verified
|
||||
$stmt->bind_param("sssssi", $email, $first_name, $last_name, $picture, $password, $is_verified);
|
||||
if ($stmt->execute()) {
|
||||
// User successfully registered, set session and redirect
|
||||
sendEmail('chrispintoza@gmail.com', '4WDCSA: New User Login', $name.' has just created an account using Google Login.');
|
||||
$_SESSION['user_id'] = $conn->insert_id;
|
||||
$_SESSION['first_name'] = $first_name;
|
||||
$_SESSION['profile_pic'] = $picture;
|
||||
processLegacyMembership($_SESSION['user_id']);
|
||||
// echo json_encode(['status' => 'success', 'message' => 'Google login successful']);
|
||||
header("Location: index");
|
||||
exit();
|
||||
} else {
|
||||
// echo json_encode(['status' => 'error', 'message' => 'Failed to register user.']);
|
||||
header("Location: index");
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
// User exists, set session and redirect
|
||||
$row = $result->fetch_assoc();
|
||||
$_SESSION['user_id'] = $row['user_id'];
|
||||
$_SESSION['first_name'] = $row['first_name'];
|
||||
$_SESSION['profile_pic'] = $row['profile_pic'];
|
||||
sendEmail('chrispintoza@gmail.com', '4WDCSA: New User Login', $name.' has just logged in using Google Login.');
|
||||
// echo json_encode(['status' => 'success', 'message' => 'Google login successful']);
|
||||
header("Location: index");
|
||||
exit();
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
} else {
|
||||
echo "Login failed.";
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Check if email and password login is requested
|
||||
if (isset($_POST['email']) && isset($_POST['password'])) {
|
||||
// CSRF Token Validation
|
||||
if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) {
|
||||
auditLog(null, 'CSRF_VALIDATION_FAILED', 'users', null, ['endpoint' => 'validate_login.php']);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Security token validation failed. Please try again.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Retrieve and validate email input
|
||||
$email = validateEmail($_POST['email']);
|
||||
if ($email === false) {
|
||||
auditLog(null, 'INVALID_EMAIL_FORMAT', 'users', null, ['email' => $_POST['email']]);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid email format.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Retrieve and sanitize password
|
||||
$password = isset($_POST['password']) ? trim($_POST['password']) : '';
|
||||
|
||||
// Basic validation
|
||||
if (empty($email) || empty($password)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Please enter both email and password.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check for account lockout
|
||||
$lockoutStatus = checkAccountLockout($email);
|
||||
if ($lockoutStatus['is_locked']) {
|
||||
auditLog(null, 'LOGIN_ATTEMPT_LOCKED_ACCOUNT', 'users', null, [
|
||||
'email' => $email,
|
||||
'locked_until' => $lockoutStatus['locked_until']
|
||||
]);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Account is temporarily locked due to multiple failed login attempts. Please try again in ' . $lockoutStatus['minutes_remaining'] . ' minutes.'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check recent failed attempts
|
||||
$recentFailedAttempts = countRecentFailedAttempts($email);
|
||||
if ($recentFailedAttempts >= 5) {
|
||||
// Lock account for 15 minutes
|
||||
lockAccount($email, 15);
|
||||
auditLog(null, 'ACCOUNT_LOCKED_THRESHOLD', 'users', null, [
|
||||
'email' => $email,
|
||||
'failed_attempts' => $recentFailedAttempts
|
||||
]);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Account locked due to multiple failed login attempts. Please try again in 15 minutes.'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Prepare SQL statement to fetch user details
|
||||
$query = "SELECT * FROM users WHERE email = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
|
||||
if (!$stmt) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Database query preparation failed.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$stmt->bind_param("s", $email);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if user exists and verify password
|
||||
if ($result->num_rows == 1) {
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
// Check if the user is verified
|
||||
if ($row['is_verified'] == 0) {
|
||||
recordLoginAttempt($email, false);
|
||||
auditLog(null, 'LOGIN_ATTEMPT_UNVERIFIED_ACCOUNT', 'users', $row['user_id']);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Your account is not verified. Please check your email for the verification link.']);
|
||||
exit();
|
||||
}
|
||||
|
||||
if (password_verify($password, $row['password'])) {
|
||||
// Record successful attempt
|
||||
recordLoginAttempt($email, true);
|
||||
|
||||
// Regenerate session ID to prevent session fixation attacks
|
||||
session_regenerate_id(true);
|
||||
|
||||
// Password is correct, set up session
|
||||
$_SESSION['user_id'] = $row['user_id'];
|
||||
$_SESSION['first_name'] = $row['first_name'];
|
||||
$_SESSION['profile_pic'] = $row['profile_pic'];
|
||||
|
||||
// Set session timeout (30 minutes)
|
||||
$_SESSION['login_time'] = time();
|
||||
$_SESSION['session_timeout'] = 1800; // 30 minutes in seconds
|
||||
|
||||
auditLog($row['user_id'], 'LOGIN_SUCCESS', 'users', $row['user_id']);
|
||||
echo json_encode(['status' => 'success', 'message' => 'Successful Login']);
|
||||
} else {
|
||||
// Password is incorrect - record failed attempt
|
||||
recordLoginAttempt($email, false);
|
||||
auditLog(null, 'LOGIN_FAILED_INVALID_PASSWORD', 'users', null, ['email' => $email]);
|
||||
|
||||
// Check if this was the threshold failure
|
||||
$newFailureCount = countRecentFailedAttempts($email);
|
||||
if ($newFailureCount >= 5) {
|
||||
lockAccount($email, 15);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Too many failed login attempts. Account locked for 15 minutes.'
|
||||
]);
|
||||
} else {
|
||||
$attemptsRemaining = 5 - $newFailureCount;
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid password. ' . $attemptsRemaining . ' attempts remaining before account lockout.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// User does not exist - still record attempt
|
||||
recordLoginAttempt($email, false);
|
||||
auditLog(null, 'LOGIN_FAILED_USER_NOT_FOUND', 'users', null, ['email' => $email]);
|
||||
echo json_encode(['status' => 'error', 'message' => 'User with that email does not exist.']);
|
||||
}
|
||||
|
||||
// Close the statement and connection
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
// Close connection
|
||||
$conn->close();
|
||||
exit();
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user