Update site: auth fixes, new admin pages, payment flow, membership renewal, helpers
This commit is contained in:
@@ -5,6 +5,11 @@ require_once($rootPath . "/src/config/connection.php");
|
||||
require_once($rootPath . "/src/config/functions.php");
|
||||
session_start();
|
||||
|
||||
// Enable error reporting for debugging
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0); // Don't display, but log them
|
||||
ini_set('log_errors', 1);
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
http_response_code(401);
|
||||
echo "Not authorized";
|
||||
@@ -32,36 +37,42 @@ echo $author_id;
|
||||
$cover_image_path = null;
|
||||
|
||||
// Only attempt upload if a file was submitted
|
||||
if (!empty($_FILES['cover_image']['name'])) {
|
||||
if (!empty($_FILES['cover_image']['name']) && $_FILES['cover_image']['error'] === UPLOAD_ERR_OK) {
|
||||
$uploadDir = $rootPath . "/uploads/blogs/" . $article_id . "/";
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0755, true);
|
||||
|
||||
// Create directory if it doesn't exist (match working pattern)
|
||||
if (!file_exists($uploadDir)) {
|
||||
mkdir($uploadDir, 0777, true);
|
||||
}
|
||||
|
||||
// Validate file using existing function
|
||||
$file_result = validateFileUpload($_FILES['cover_image'], 'profile_picture');
|
||||
if ($file_result === false) {
|
||||
// Simple validation - check extension
|
||||
$extension = strtolower(pathinfo($_FILES['cover_image']['name'], PATHINFO_EXTENSION));
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
|
||||
if (!in_array($extension, $allowedExtensions)) {
|
||||
http_response_code(400);
|
||||
echo "Invalid file upload";
|
||||
echo "Invalid file type. Allowed: jpg, jpeg, png, gif, webp";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Use fixed filename "cover" to avoid creating multiple copies on autosave
|
||||
$extension = $file_result['extension'];
|
||||
$filename = "cover." . $extension;
|
||||
|
||||
// Delete old cover if it exists with different extension
|
||||
array_map('unlink', glob($uploadDir . "cover.*"));
|
||||
$oldCovers = glob($uploadDir . "cover.*");
|
||||
if ($oldCovers) {
|
||||
foreach ($oldCovers as $oldCover) {
|
||||
@unlink($oldCover);
|
||||
}
|
||||
}
|
||||
|
||||
$targetPath = $uploadDir . $filename;
|
||||
$cover_image_path = "/uploads/blogs/" . $article_id . "/" . $filename;
|
||||
|
||||
// Move the uploaded file
|
||||
if (move_uploaded_file($_FILES['cover_image']['tmp_name'], $targetPath)) {
|
||||
// File moved successfully, $cover_image_path is set
|
||||
} else {
|
||||
if (!move_uploaded_file($_FILES['cover_image']['tmp_name'], $targetPath)) {
|
||||
http_response_code(500);
|
||||
echo "Failed to move uploaded file.";
|
||||
echo "Failed to move uploaded file";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ if (isset($_FILES['cover_image']) && $_FILES['cover_image']['error'] === UPLOAD_
|
||||
$upload_dir = $rootPath . '/uploads/blogs/' . $folder_id . '/';
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0755, true);
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
// Validate and process the file
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
ob_start();
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . '/src/config/functions.php');
|
||||
require_once($rootPath . '/src/config/connection.php');
|
||||
|
||||
// Check admin status
|
||||
session_start();
|
||||
if (empty($_SESSION['user_id'])) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_role = getUserRole();
|
||||
if (!in_array($user_role, ['admin', 'superadmin'])) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$course_id = intval($_POST['course_id'] ?? 0);
|
||||
|
||||
if ($course_id <= 0) {
|
||||
throw new Exception('Invalid course ID');
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("DELETE FROM courses WHERE course_id = ?");
|
||||
$stmt->bind_param("i", $course_id);
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception('Failed to delete course: ' . $stmt->error);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'success', 'message' => 'Course deleted successfully']);
|
||||
|
||||
} catch (Exception $e) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,46 +1,76 @@
|
||||
<?php
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
include_once($rootPath . '/header.php');
|
||||
checkAdmin();
|
||||
|
||||
<?php
|
||||
ob_start();
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$event_id = $_POST['event_id'] ?? null;
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . '/src/config/functions.php');
|
||||
require_once($rootPath . '/src/config/connection.php');
|
||||
|
||||
if (!$event_id) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Event ID is required']);
|
||||
// Start session if not already started
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Check admin status
|
||||
if (empty($_SESSION['user_id'])) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Get event details to delete associated files
|
||||
$stmt = $conn->prepare("SELECT image, promo FROM events WHERE event_id = ?");
|
||||
$stmt->bind_param("i", $event_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
$event = $result->fetch_assoc();
|
||||
|
||||
// Delete image files
|
||||
if ($event['image'] && file_exists($rootPath . '/' . $event['image'])) {
|
||||
unlink($rootPath . '/' . $event['image']);
|
||||
}
|
||||
if ($event['promo'] && file_exists($rootPath . '/' . $event['promo'])) {
|
||||
unlink($rootPath . '/' . $event['promo']);
|
||||
}
|
||||
|
||||
// Delete from database
|
||||
$delete_stmt = $conn->prepare("DELETE FROM events WHERE event_id = ?");
|
||||
$delete_stmt->bind_param("i", $event_id);
|
||||
|
||||
if ($delete_stmt->execute()) {
|
||||
echo json_encode(['status' => 'success', 'message' => 'Event deleted successfully']);
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to delete event']);
|
||||
}
|
||||
$delete_stmt->close();
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Event not found']);
|
||||
$user_role = getUserRole();
|
||||
if (!in_array($user_role, ['admin', 'superadmin'])) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
try {
|
||||
$event_id = intval($_POST['event_id'] ?? 0);
|
||||
|
||||
if ($event_id <= 0) {
|
||||
throw new Exception('Invalid event ID');
|
||||
}
|
||||
|
||||
// Get event details to delete associated files
|
||||
$stmt = $conn->prepare("SELECT image, promo FROM events WHERE event_id = ?");
|
||||
$stmt->bind_param("i", $event_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
if ($result->num_rows > 0) {
|
||||
$event = $result->fetch_assoc();
|
||||
|
||||
// Delete image files
|
||||
if ($event['image'] && file_exists($rootPath . '/' . $event['image'])) {
|
||||
unlink($rootPath . '/' . $event['image']);
|
||||
}
|
||||
if ($event['promo'] && file_exists($rootPath . '/' . $event['promo'])) {
|
||||
unlink($rootPath . '/' . $event['promo']);
|
||||
}
|
||||
|
||||
// Delete from database
|
||||
$delete_stmt = $conn->prepare("DELETE FROM events WHERE event_id = ?");
|
||||
$delete_stmt->bind_param("i", $event_id);
|
||||
|
||||
if ($delete_stmt->execute()) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'success', 'message' => 'Event deleted successfully']);
|
||||
} else {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to delete event']);
|
||||
}
|
||||
$delete_stmt->close();
|
||||
} else {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Event not found']);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
|
||||
} catch (Exception $e) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Insert into the membership fees table
|
||||
$payment_amount = calculateProrata(210); // Assuming a fixed membership fee, adjust as needed
|
||||
$payment_amount = calculateProrata();
|
||||
$payment_date = date('Y-m-d');
|
||||
$membership_start_date = $payment_date;
|
||||
// $membership_end_date = date('Y-12-31');
|
||||
|
||||
@@ -3,6 +3,7 @@ $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");
|
||||
require_once($rootPath . "/src/helpers/notification_helper.php");
|
||||
|
||||
// Start session to retrieve the logged-in user's ID
|
||||
session_start();
|
||||
@@ -79,6 +80,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$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()) {
|
||||
// Get booking id and audit
|
||||
$booking_id = $conn->insert_id;
|
||||
if (function_exists('auditLog')) {
|
||||
auditLog($user_id, 'BOOKING_CREATED', 'bookings', $booking_id, ['total_amount' => $total_amount, 'from' => $from_date, 'to' => $to_date]);
|
||||
}
|
||||
$event = 'new_booking_created';
|
||||
$sub_feed = 'bookings';
|
||||
$data = [
|
||||
'actor_id' => $_SESSION['user_id'] ?? null,
|
||||
'actor_avatar' => $_SESSION['profile_pic'] ?? null, // used by UI to show avatar
|
||||
'title' => "New Booking Created with Booking ID: {$booking_id}"
|
||||
];
|
||||
addNotification(null, $event, $sub_feed, $data, null);
|
||||
// Redirect to success page or display success message
|
||||
echo "<script>alert('Booking successfully created!'); window.location.href = 'booking.php';</script>";
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
ob_start();
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$rootPath = dirname(dirname(__DIR__));
|
||||
require_once($rootPath . "/src/config/env.php");
|
||||
require_once($rootPath . '/src/config/functions.php');
|
||||
require_once($rootPath . '/src/config/connection.php');
|
||||
|
||||
// Check admin status
|
||||
session_start();
|
||||
if (empty($_SESSION['user_id'])) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_role = getUserRole();
|
||||
if (!in_array($user_role, ['admin', 'superadmin'])) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Unauthorized access']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$course_id = $_POST['course_id'] ?? null;
|
||||
$course_type = trim($_POST['course_type'] ?? '');
|
||||
$code = trim($_POST['code'] ?? '');
|
||||
$date = trim($_POST['date'] ?? '');
|
||||
$capacity = intval($_POST['capacity'] ?? 0);
|
||||
$cost_members = floatval($_POST['cost_members'] ?? 0);
|
||||
$cost_nonmembers = floatval($_POST['cost_nonmembers'] ?? 0);
|
||||
$instructor = trim($_POST['instructor'] ?? '');
|
||||
$instructor_email = trim($_POST['instructor_email'] ?? '');
|
||||
|
||||
$allowed_types = ['driver_training','bush_mechanics','rescue_recovery','ladies_driver_training'];
|
||||
|
||||
if (!in_array($course_type, $allowed_types)) {
|
||||
throw new Exception('Invalid course type');
|
||||
}
|
||||
|
||||
if (empty($date) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
|
||||
throw new Exception('Invalid date format');
|
||||
}
|
||||
|
||||
// If code not provided, generate from type + date using ABBR_MMDD format
|
||||
if (empty($code)) {
|
||||
$abbrMap = [
|
||||
'driver_training' => 'DRVTRN',
|
||||
'bush_mechanics' => 'BUSHMEC',
|
||||
'rescue_recovery' => 'RESREC',
|
||||
'ladies_driver_training' => 'LADYTRN'
|
||||
];
|
||||
|
||||
$abbr = $abbrMap[$course_type] ?? strtoupper(preg_replace('/[^A-Z0-9]/', '', $course_type));
|
||||
// ensure abbr fits (reserve 1 char for underscore and 4 for MMDD)
|
||||
$abbr = substr($abbr, 0, 7);
|
||||
$mmdd = date('md', strtotime($date));
|
||||
$code = strtoupper(substr($abbr . '_' . $mmdd, 0, 12));
|
||||
}
|
||||
|
||||
if ($capacity <= 0) {
|
||||
throw new Exception('Capacity must be greater than 0');
|
||||
}
|
||||
|
||||
if (empty($instructor)) {
|
||||
throw new Exception('Instructor name is required');
|
||||
}
|
||||
|
||||
if ($course_id) {
|
||||
// Update
|
||||
$stmt = $conn->prepare("UPDATE courses SET course_type = ?, code = ?, date = ?, capacity = ?, cost_members = ?, cost_nonmembers = ?, instructor = ?, instructor_email = ? WHERE course_id = ?");
|
||||
$stmt->bind_param("sssiddssi", $course_type, $code, $date, $capacity, $cost_members, $cost_nonmembers, $instructor, $instructor_email, $course_id);
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception('Failed to update course: ' . $stmt->error);
|
||||
}
|
||||
$stmt->close();
|
||||
} else {
|
||||
// Insert - booked defaults to 0
|
||||
$stmt = $conn->prepare("INSERT INTO courses (course_type, code, date, capacity, booked, cost_members, cost_nonmembers, instructor, instructor_email) VALUES (?, ?, ?, ?, 0, ?, ?, ?, ?)");
|
||||
$stmt->bind_param("sssiddss", $course_type, $code, $date, $capacity, $cost_members, $cost_nonmembers, $instructor, $instructor_email);
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
throw new Exception('Failed to create course: ' . $stmt->error);
|
||||
}
|
||||
|
||||
$course_id = $conn->insert_id;
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'success', 'message' => $course_id ? 'Course saved successfully' : 'Course created successfully', 'course_id' => $course_id]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -3,6 +3,7 @@ $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");
|
||||
require_once($rootPath . "/src/helpers/notification_helper.php");
|
||||
session_start();
|
||||
|
||||
|
||||
@@ -93,10 +94,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
$status = "AWAITING PAYMENT";
|
||||
$type = 'course';
|
||||
$payment_id = uniqid();
|
||||
$payment_id = generatePaymentRef('COURSE', $course_id, $user_id);
|
||||
$publicRef = bin2hex(random_bytes(16));
|
||||
$num_vehicles = 1;
|
||||
$discountAmount = 0;
|
||||
$eft_id = strtoupper("COURSE ".date("m-d", strtotime($date))." ".getInitialSurname($user_id));
|
||||
$eft_id = $payment_id;
|
||||
$notes = "";
|
||||
if ($pending_member){
|
||||
$notes = "Membership Payment pending at time of booking. Please confirm payment has been received.";
|
||||
@@ -117,6 +119,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if ($stmt->execute()) {
|
||||
$booking_id = $conn->insert_id;
|
||||
|
||||
// Audit booking creation
|
||||
if (function_exists('auditLog')) {
|
||||
auditLog($user_id, 'COURSE_BOOKING_CREATED', 'bookings', $booking_id, ['course_id' => $course_id, 'payment_id' => $payment_id, 'amount' => $payment_amount]);
|
||||
}
|
||||
$event = 'new_course_booking_created';
|
||||
$sub_feed = 'bookings';
|
||||
$data = [
|
||||
'actor_id' => $_SESSION['user_id'] ?? null,
|
||||
'actor_avatar' => $_SESSION['profile_pic'] ?? null, // used by UI to show avatar
|
||||
'title' => "New Course Booking Created : {$payment_id}"
|
||||
];
|
||||
addNotification(null, $event, $sub_feed, $data, null);
|
||||
|
||||
if ($payment_amount < 1) {
|
||||
if (processZeroPayment($payment_id, $payment_amount, $description)) {
|
||||
echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
@@ -125,11 +140,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
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);
|
||||
// Create payments row
|
||||
$pstmt = $conn->prepare("INSERT INTO payments (payment_id, user_id, amount, status, description, booking_id, public_ref) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
if ($pstmt) {
|
||||
$pstmt->bind_param('sidssis', $payment_id, $user_id, $payment_amount, $status, $description, $booking_id, $publicRef);
|
||||
$pstmt->execute();
|
||||
$pstmt->close();
|
||||
}
|
||||
|
||||
// Create iKhokha payment link
|
||||
$resp = createIkhokhaPayment($payment_id, $payment_amount, $description, $publicRef);
|
||||
|
||||
// Send invoice and admin notification (keep for records)
|
||||
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
|
||||
|
||||
// Redirect user to payment link if available
|
||||
$paylink = $resp['paylinkUrl'] ?? $resp['paylinkURL'] ?? $resp['paylink_url'] ?? null;
|
||||
if ($paylink) {
|
||||
header('Location: ' . $paylink);
|
||||
exit();
|
||||
} else {
|
||||
// Fallback: redirect to legacy payment confirmation page
|
||||
header("Location: payment_confirmation?token=".encryptData($booking_id, $salt));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Handle error if insert fails and echo the MySQL error
|
||||
|
||||
@@ -78,19 +78,17 @@ if (!$name || !$type || !$location || !$date || !$time || !$feature || !$descrip
|
||||
$image_path = null;
|
||||
if (!empty($_FILES['image']['name'])) {
|
||||
$upload_dir = $rootPath . '/assets/images/events/';
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0755, true);
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
$file_name = uniqid() . '_' . basename($_FILES['image']['name']);
|
||||
$target_file = $upload_dir . $file_name;
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
$file_type = finfo_file($finfo, $_FILES['image']['tmp_name']);
|
||||
finfo_close($finfo);
|
||||
|
||||
// Validate image file
|
||||
$allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (!in_array($file_type, $allowed_types)) {
|
||||
// Validate file extension
|
||||
$ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
|
||||
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
if (!in_array($ext, $allowed_extensions)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid image file type. Only JPEG, PNG, GIF, and WebP are allowed']);
|
||||
exit;
|
||||
}
|
||||
@@ -110,19 +108,17 @@ if (!empty($_FILES['image']['name'])) {
|
||||
$promo_path = null;
|
||||
if (!empty($_FILES['promo']['name'])) {
|
||||
$upload_dir = $rootPath . '/assets/images/events/';
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0755, true);
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
$file_name = uniqid() . '_promo_' . basename($_FILES['promo']['name']);
|
||||
$target_file = $upload_dir . $file_name;
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
$file_type = finfo_file($finfo, $_FILES['promo']['tmp_name']);
|
||||
finfo_close($finfo);
|
||||
|
||||
// Validate image file
|
||||
$allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (!in_array($file_type, $allowed_types)) {
|
||||
// Validate file extension
|
||||
$ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
|
||||
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
if (!in_array($ext, $allowed_extensions)) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid promo image file type. Only JPEG, PNG, GIF, and WebP are allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -15,64 +15,92 @@ 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 = ?";
|
||||
// Fetch the membership fee record for this user
|
||||
$query = "SELECT fee_id, payment_amount, payment_status, membership_end_date FROM membership_fees WHERE user_id = ?";
|
||||
$stmt = $conn->prepare($query);
|
||||
if (!$stmt) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Server error preparing statement']);
|
||||
exit();
|
||||
}
|
||||
$stmt->bind_param('i', $user_id);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// Check if trip exists
|
||||
// Check if membership fee exists
|
||||
if ($result->num_rows === 0) {
|
||||
$response = ['error' => 'Application Fee not found.'];
|
||||
$response = ['error' => 'Membership fee not found.'];
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Fetch trip details
|
||||
// Fetch fee details
|
||||
$fee = $result->fetch_assoc();
|
||||
$fee_id = isset($fee['fee_id']) ? intval($fee['fee_id']) : null;
|
||||
$payment_status = $fee['payment_status'];
|
||||
$membership_end_date = $fee['membership_end_date'];
|
||||
$payment_amount = intval($fee['payment_amount']);
|
||||
$payment_amount = floatval($fee['payment_amount']);
|
||||
$publicRef = bin2hex(random_bytes(16));
|
||||
|
||||
$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.");
|
||||
// Persist the generated payment_id back to the membership_fees row (use fee_id to be precise)
|
||||
$updateStmt = $conn->prepare("UPDATE membership_fees SET payment_id = ? WHERE fee_id = ?");
|
||||
if ($updateStmt) {
|
||||
$updateStmt->bind_param("si", $payment_id, $fee_id);
|
||||
if (!$updateStmt->execute()) {
|
||||
throw new Exception("Failed to update membership_fees table: " . $updateStmt->error);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
$updateStmt->close();
|
||||
} else {
|
||||
throw new Exception("Failed to prepare statement for membership_fees table: " . $conn->error);
|
||||
}
|
||||
|
||||
// Get the current date
|
||||
$current_date = new DateTime();
|
||||
// If the amount is zero, treat as paid immediately
|
||||
if ($payment_amount < 1) {
|
||||
if (processZeroPayment($payment_id, $payment_amount, $description)) {
|
||||
// Update membership_fees status to PAID
|
||||
$paidStmt = $conn->prepare("UPDATE membership_fees SET payment_status = 'PAID' WHERE fee_id = ?");
|
||||
if ($paidStmt) {
|
||||
$paidStmt->bind_param('i', $fee_id);
|
||||
$paidStmt->execute();
|
||||
$paidStmt->close();
|
||||
}
|
||||
echo "<script>alert('Membership payment recorded.'); window.location.href = 'memberships.php';</script>";
|
||||
exit();
|
||||
} else {
|
||||
echo "<script>alert('Failed to process membership payment.'); window.location.href = 'memberships.php';</script>";
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
// Create payments row
|
||||
$status = "AWAITING PAYMENT";
|
||||
$pstmt = $conn->prepare("INSERT INTO payments (payment_id, user_id, amount, status, description, public_ref) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
if ($pstmt) {
|
||||
$pstmt->bind_param('sidsss', $payment_id, $user_id, $payment_amount, $status, $description, $publicRef);
|
||||
$pstmt->execute();
|
||||
$pstmt->close();
|
||||
}
|
||||
|
||||
// Convert $membership_end_date to a DateTime object
|
||||
$membership_end_date_obj = DateTime::createFromFormat('Y-m-d', $membership_end_date);
|
||||
// Create iKhokha payment link
|
||||
$resp = createIkhokhaPayment($payment_id, $payment_amount, $description, $publicRef);
|
||||
|
||||
// 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")
|
||||
) {
|
||||
// Send invoice and admin notification if desired
|
||||
// sendInvoice(getEmail($user_id), getFullName($user_id), 'MEMBERSHIP-'.date('Y'), formatCurrency($payment_amount), $description);
|
||||
sendAdminNotification('Membership Payment Initiated - '.getFullName($user_id), getFullName($user_id).' initiated a membership payment.');
|
||||
|
||||
// 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
|
||||
// Redirect user to payment link if available
|
||||
$paylink = $resp['paylinkUrl'] ?? $resp['paylinkURL'] ?? $resp['paylink_url'] ?? null;
|
||||
if ($paylink) {
|
||||
header('Location: ' . $paylink);
|
||||
exit();
|
||||
} else {
|
||||
// Fallback: redirect to a membership page with an encrypted token
|
||||
header("Location: membership_confirmation?token=" . encryptData($payment_id, $salt));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ if (isset($_POST['signature'])) {
|
||||
$filePath = $rootPath . '/uploads/signatures/' . $fileName;
|
||||
|
||||
// Ensure the directory exists
|
||||
if (!is_dir($rootPath . '/uploads/signatures')) {
|
||||
if (!file_exists($rootPath . '/uploads/signatures')) {
|
||||
mkdir($rootPath . '/uploads/signatures', 0777, true);
|
||||
}
|
||||
|
||||
@@ -56,17 +56,122 @@ if (isset($_POST['signature'])) {
|
||||
$stmt->bind_param('si', $display_path, $user_id);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
// Audit: signature saved
|
||||
if (function_exists('auditLog')) {
|
||||
auditLog($user_id, 'SIGNATURE_SAVED', 'membership_application', null, ['path' => $display_path]);
|
||||
}
|
||||
// Check the payment status
|
||||
$paymentStatus = checkMembershipPaymentStatus($user_id) ? 'PAID' : 'NOT_PAID';
|
||||
|
||||
// Respond with the appropriate redirect URL based on the payment status
|
||||
// If not paid, create a payments row (if missing) and initiate iKhokha paylink
|
||||
$paylink = null;
|
||||
if ($paymentStatus !== 'PAID') {
|
||||
// Fetch the membership fee row to get amount and payment_id
|
||||
$mfStmt = $conn->prepare("SELECT fee_id, payment_amount, payment_id FROM membership_fees WHERE user_id = ? ORDER BY fee_id DESC LIMIT 1");
|
||||
if ($mfStmt) {
|
||||
$mfStmt->bind_param('i', $user_id);
|
||||
$mfStmt->execute();
|
||||
$mfRes = $mfStmt->get_result();
|
||||
$mf = $mfRes->fetch_assoc();
|
||||
$mfStmt->close();
|
||||
} else {
|
||||
$mf = null;
|
||||
}
|
||||
|
||||
if ($mf && isset($mf['payment_amount'])) {
|
||||
$amount = floatval($mf['payment_amount']);
|
||||
// Use existing payment_id or generate one
|
||||
$payment_id = $mf['payment_id'] ?? generatePaymentRef('SUBS', null, $user_id);;
|
||||
|
||||
if (empty($mf['payment_id'])) {
|
||||
// Persist generated payment_id back to membership_fees
|
||||
$u = $conn->prepare("UPDATE membership_fees SET payment_id = ? WHERE fee_id = ?");
|
||||
if ($u) {
|
||||
$u->bind_param('si', $payment_id, $mf['fee_id']);
|
||||
$u->execute();
|
||||
$u->close();
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure a payments row exists
|
||||
$checkP = $conn->prepare("SELECT COUNT(*) AS cnt FROM payments WHERE payment_id = ? LIMIT 1");
|
||||
if ($checkP) {
|
||||
$checkP->bind_param('s', $payment_id);
|
||||
$checkP->execute();
|
||||
$r = $checkP->get_result()->fetch_assoc();
|
||||
$exists = intval($r['cnt']) > 0;
|
||||
$checkP->close();
|
||||
} else {
|
||||
$exists = false;
|
||||
}
|
||||
|
||||
if (!$exists) {
|
||||
$publicRef = bin2hex(random_bytes(16));
|
||||
// If current month is December, attribute the membership year to the next year
|
||||
$currentYear = intval(date('Y'));
|
||||
$month = intval(date('n'));
|
||||
if ($month === 12) {
|
||||
$membershipYear = $currentYear + 1;
|
||||
} else {
|
||||
$membershipYear = $currentYear;
|
||||
}
|
||||
$description = 'Membership Fees ' . $membershipYear . ' ' . getInitialSurname($user_id);
|
||||
$status = 'AWAITING PAYMENT';
|
||||
$ins = $conn->prepare("INSERT INTO payments (payment_id, user_id, amount, status, description, public_ref) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
if ($ins) {
|
||||
$ins->bind_param('sidsss', $payment_id, $user_id, $amount, $status, $description, $publicRef);
|
||||
if ($ins->execute()) {
|
||||
// Audit: payment row created for membership
|
||||
if (function_exists('auditLog')) {
|
||||
auditLog($user_id, 'MEMBERSHIP_PAYMENT_CREATED', 'payments', null, ['payment_id' => $payment_id, 'amount' => $amount]);
|
||||
}
|
||||
}
|
||||
$ins->close();
|
||||
}
|
||||
}
|
||||
|
||||
// Create iKhokha paylink via helper (functions.php)
|
||||
try {
|
||||
$publicRef = $publicRef ?? bin2hex(random_bytes(16));
|
||||
$resp = createIkhokhaPayment($payment_id, $amount, $desc ?? ('Membership Fee ' . date('Y')), $publicRef);
|
||||
$paylink = $resp['paylinkUrl'] ?? $resp['paylinkURL'] ?? $resp['paylink_url'] ?? null;
|
||||
// After creating paylink, update paymentStatus to AWAITING PAYMENT
|
||||
$paymentStatus = $paylink ? 'AWAITING PAYMENT' : $paymentStatus;
|
||||
$token = encryptData($payment_id, $_ENV['SALT']);
|
||||
// Audit: paylink created (or attempted)
|
||||
if (function_exists('auditLog')) {
|
||||
auditLog($user_id, 'IKHOKHA_PAYLINK_CREATED', 'payments', null, ['payment_id' => $payment_id, 'paylink' => $paylink]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// Log but do not fail signature save
|
||||
error_log('iKhokha create error: ' . $e->getMessage());
|
||||
if (function_exists('auditLog')) {
|
||||
auditLog($user_id, 'IKHOKHA_PAYLINK_FAILED', 'payments', null, ['payment_id' => $payment_id, 'error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Respond with the appropriate redirect URL and paylink (if created)
|
||||
ob_end_clean();
|
||||
echo json_encode([
|
||||
$response = [
|
||||
'status' => 'success',
|
||||
'message' => 'Signature saved successfully!',
|
||||
'paymentStatus' => $paymentStatus // Send payment status
|
||||
]);
|
||||
'paymentStatus' => $paymentStatus,
|
||||
'token' => $token ?? null
|
||||
];
|
||||
if (!empty($paylink)) {
|
||||
$response['paylinkUrl'] = $paylink;
|
||||
}
|
||||
if (!empty($payment_id)) {
|
||||
$response['payment_id'] = $payment_id;
|
||||
}
|
||||
echo json_encode($response);
|
||||
} else {
|
||||
// Audit: signature save failed
|
||||
if (function_exists('auditLog')) {
|
||||
auditLog($user_id, 'SIGNATURE_SAVE_FAILED', 'membership_application', null, ['user_id' => $user_id]);
|
||||
}
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Database update failed']);
|
||||
}
|
||||
@@ -78,6 +183,10 @@ if (isset($_POST['signature'])) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to save signature']);
|
||||
}
|
||||
} else {
|
||||
// Audit: no signature provided in request
|
||||
if (function_exists('auditLog') && isset($_SESSION['user_id'])) {
|
||||
auditLog($_SESSION['user_id'], 'SIGNATURE_NOT_PROVIDED', 'membership_application', null, ['endpoint' => 'process_signature.php']);
|
||||
}
|
||||
ob_end_clean();
|
||||
echo json_encode(['status' => 'error', 'message' => 'Signature not provided']);
|
||||
}
|
||||
|
||||
@@ -136,8 +136,8 @@ try {
|
||||
$upload_dir = $rootPath . '/assets/images/trips/';
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0755, true);
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
|
||||
@@ -3,6 +3,7 @@ $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");
|
||||
require_once($rootPath . "/src/helpers/notification_helper.php");
|
||||
session_start();
|
||||
|
||||
// Get the trip_id from the request (ensure it's sanitized)
|
||||
@@ -78,6 +79,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$member_discount = $cost_nonmembers - $cost_members;
|
||||
$member_discount_pensioner = $cost_pensioner - $cost_pensioner_member;
|
||||
$booking_fee = $trip['booking_fee'];
|
||||
// Radio option (boolean/int) — ensure defined from POST
|
||||
$radio = isset($_POST['radio']) ? intval($_POST['radio']) : 0;
|
||||
$radioCost = $radio ? 50 : 0;
|
||||
$start_date = $trip['start_date']; // Start date of the trip
|
||||
$end_date = $trip['end_date']; // End date of the trip
|
||||
@@ -103,9 +106,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$status = "AWAITING PAYMENT";
|
||||
$description = $trip_name;
|
||||
$type = 'trip';
|
||||
$payment_id = uniqid();
|
||||
$payment_id = generatePaymentRef('TRIP', $trip_id, $user_id);
|
||||
$publicRef = bin2hex(random_bytes(16));
|
||||
// $eft_id = strtoupper(base_convert(time(), 10, 36)); // Convert timestamp to base36
|
||||
$eft_id = strtoupper($trip_code." ".getInitialSurname($user_id));
|
||||
// $eft_id = strtoupper($trip_code." ".getInitialSurname($user_id));
|
||||
|
||||
|
||||
// Insert booking into the database
|
||||
@@ -123,6 +127,21 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Get the generated booking_id
|
||||
$booking_id = $conn->insert_id;
|
||||
|
||||
// Audit booking creation
|
||||
if (function_exists('auditLog')) {
|
||||
auditLog($user_id, 'TRIP_BOOKING_CREATED', 'bookings', $booking_id, ['trip_id' => $trip_id, 'payment_id' => $payment_id, 'amount' => $payment_amount]);
|
||||
}
|
||||
|
||||
// Create notification for new booking
|
||||
$event = 'new_trip_booking_created';
|
||||
$sub_feed = 'bookings';
|
||||
$data = [
|
||||
'actor_id' => $_SESSION['user_id'] ?? null,
|
||||
'actor_avatar' => $_SESSION['profile_pic'] ?? null, // used by UI to show avatar
|
||||
'title' => "New Trip Booking Created: {$payment_id}"
|
||||
];
|
||||
addNotification(null, $event, $sub_feed, $data, null);
|
||||
|
||||
if ($payment_amount < 1) {
|
||||
if (processZeroPayment($payment_id, $payment_amount, $description)) {
|
||||
echo "<script>alert('Booking successfully created!'); window.location.href = 'bookings.php';</script>";
|
||||
@@ -131,11 +150,29 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
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 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
|
||||
// Create payments row
|
||||
$pstmt = $conn->prepare("INSERT INTO payments (payment_id, user_id, amount, status, description, booking_id, public_ref) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||
if ($pstmt) {
|
||||
$pstmt->bind_param('sidssis', $payment_id, $user_id, $payment_amount, $status, $description, $booking_id, $publicRef);
|
||||
$pstmt->execute();
|
||||
$pstmt->close();
|
||||
}
|
||||
|
||||
// Create iKhokha payment link
|
||||
$resp = createIkhokhaPayment($payment_id, $payment_amount, $description, $publicRef);
|
||||
|
||||
// Send invoice and admin notification
|
||||
sendAdminNotification('New Trip Booking - '.getFullName($user_id), getFullName($user_id).' has booked for '.$description);
|
||||
|
||||
// Redirect to payment link if available
|
||||
$paylink = $resp['paylinkUrl'] ?? $resp['paylinkURL'] ?? $resp['paylink_url'] ?? null;
|
||||
if ($paylink) {
|
||||
header('Location: ' . $paylink);
|
||||
exit();
|
||||
} else {
|
||||
header("Location: payment_confirmation?token=".encryptData($booking_id, $salt));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Handle error if insert fails and echo the MySQL error
|
||||
|
||||
@@ -52,26 +52,25 @@ try {
|
||||
|
||||
// Create album directory
|
||||
$albumDir = $rootPath . '/assets/uploads/gallery/' . $album_id;
|
||||
if (!is_dir($albumDir)) {
|
||||
if (!mkdir($albumDir, 0755, true)) {
|
||||
throw new Exception('Failed to create album directory');
|
||||
}
|
||||
if (!file_exists($albumDir)) {
|
||||
mkdir($albumDir, 0777, true);
|
||||
}
|
||||
|
||||
// Handle cover image upload
|
||||
$coverImagePath = null;
|
||||
if (isset($_FILES['cover_image']) && $_FILES['cover_image']['error'] !== UPLOAD_ERR_NO_FILE) {
|
||||
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (isset($_FILES['cover_image']) && $_FILES['cover_image']['error'] === UPLOAD_ERR_OK) {
|
||||
$maxSize = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
$fileName = $_FILES['cover_image']['name'];
|
||||
$fileTmpName = $_FILES['cover_image']['tmp_name'];
|
||||
$fileSize = $_FILES['cover_image']['size'];
|
||||
$fileMime = mime_content_type($fileTmpName);
|
||||
|
||||
// Validate file extension
|
||||
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
|
||||
// Validate file
|
||||
if (!in_array($fileMime, $allowedMimes)) {
|
||||
throw new Exception('Invalid cover image file type');
|
||||
if (!in_array($ext, $allowedExtensions)) {
|
||||
throw new Exception('Invalid cover image file type. Allowed: jpg, jpeg, png, gif, webp');
|
||||
}
|
||||
|
||||
if ($fileSize > $maxSize) {
|
||||
@@ -96,8 +95,7 @@ try {
|
||||
}
|
||||
|
||||
// Handle photo uploads
|
||||
if (isset($_FILES['photos']) && $_FILES['photos']['error'][0] !== UPLOAD_ERR_NO_FILE) {
|
||||
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (isset($_FILES['photos']) && $_FILES['photos']['error'][0] === UPLOAD_ERR_OK) {
|
||||
$maxSize = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
$displayOrder = 1;
|
||||
@@ -111,11 +109,13 @@ try {
|
||||
$fileName = $_FILES['photos']['name'][$i];
|
||||
$fileTmpName = $_FILES['photos']['tmp_name'][$i];
|
||||
$fileSize = $_FILES['photos']['size'][$i];
|
||||
$fileMime = mime_content_type($fileTmpName);
|
||||
|
||||
// Validate file extension
|
||||
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
|
||||
// Validate file
|
||||
if (!in_array($fileMime, $allowedMimes)) {
|
||||
throw new Exception('Invalid file type: ' . $fileName);
|
||||
if (!in_array($ext, $allowedExtensions)) {
|
||||
throw new Exception('Invalid file type: ' . $fileName . '. Allowed: jpg, jpeg, png, gif, webp');
|
||||
}
|
||||
|
||||
if ($fileSize > $maxSize) {
|
||||
|
||||
@@ -43,14 +43,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$filename = str_replace(' ', '_', $eft_id) . '.pdf';
|
||||
$target_file = $target_dir . $filename;
|
||||
|
||||
// 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;
|
||||
// Make sure target directory exists
|
||||
if (!file_exists($target_dir)) {
|
||||
mkdir($target_dir, 0777, true);
|
||||
}
|
||||
|
||||
if (move_uploaded_file($_FILES['pop_file']['tmp_name'], $target_file)) {
|
||||
|
||||
@@ -76,25 +76,29 @@ try {
|
||||
$updateStmt->close();
|
||||
|
||||
// Handle cover image upload if provided
|
||||
if (isset($_FILES['cover_image']) && $_FILES['cover_image']['error'] !== UPLOAD_ERR_NO_FILE) {
|
||||
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
$maxSize = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
if (isset($_FILES['cover_image']) && $_FILES['cover_image']['error'] === UPLOAD_ERR_OK) {
|
||||
$fileName = $_FILES['cover_image']['name'];
|
||||
$fileTmpName = $_FILES['cover_image']['tmp_name'];
|
||||
$fileSize = $_FILES['cover_image']['size'];
|
||||
$fileMime = mime_content_type($fileTmpName);
|
||||
|
||||
// Validate file
|
||||
if (!in_array($fileMime, $allowedMimes)) {
|
||||
throw new Exception('Invalid cover image file type');
|
||||
|
||||
// Validate file extension
|
||||
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
|
||||
if (!in_array($ext, $allowedExtensions)) {
|
||||
throw new Exception('Invalid cover image file type. Allowed: jpg, jpeg, png, gif, webp');
|
||||
}
|
||||
|
||||
if ($fileSize > $maxSize) {
|
||||
if ($fileSize > 5 * 1024 * 1024) {
|
||||
throw new Exception('Cover image file too large (max 5MB)');
|
||||
}
|
||||
|
||||
$albumDir = $rootPath . '/assets/uploads/gallery/' . $album_id;
|
||||
|
||||
// Create directory if it doesn't exist (match working pattern)
|
||||
if (!file_exists($albumDir)) {
|
||||
mkdir($albumDir, 0777, true);
|
||||
}
|
||||
|
||||
// Delete old cover if it exists
|
||||
$oldCoverStmt = $conn->prepare("SELECT cover_image FROM photo_albums WHERE album_id = ?");
|
||||
@@ -104,16 +108,15 @@ try {
|
||||
if ($oldCoverResult->num_rows > 0) {
|
||||
$oldCover = $oldCoverResult->fetch_assoc();
|
||||
if ($oldCover['cover_image']) {
|
||||
$oldCoverPath = $_SERVER['DOCUMENT_ROOT'] . $oldCover['cover_image'];
|
||||
$oldCoverPath = $rootPath . $oldCover['cover_image'];
|
||||
if (file_exists($oldCoverPath)) {
|
||||
unlink($oldCoverPath);
|
||||
@unlink($oldCoverPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
$oldCoverStmt->close();
|
||||
|
||||
// Generate unique filename
|
||||
$ext = pathinfo($fileName, PATHINFO_EXTENSION);
|
||||
$newFileName = 'cover_' . uniqid() . '.' . $ext;
|
||||
$filePath = $albumDir . '/' . $newFileName;
|
||||
$coverImagePath = '/assets/uploads/gallery/' . $album_id . '/' . $newFileName;
|
||||
@@ -130,12 +133,15 @@ try {
|
||||
}
|
||||
|
||||
// Handle photo uploads if any
|
||||
if (isset($_FILES['photos']) && $_FILES['photos']['error'][0] !== UPLOAD_ERR_NO_FILE) {
|
||||
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (isset($_FILES['photos']) && $_FILES['photos']['error'][0] === UPLOAD_ERR_OK) {
|
||||
$maxSize = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
$albumDir = $rootPath . '/assets/uploads/gallery/' . $album_id;
|
||||
|
||||
// Create directory if it doesn't exist (match working pattern)
|
||||
if (!file_exists($albumDir)) {
|
||||
mkdir($albumDir, 0777, true);
|
||||
}
|
||||
|
||||
// Get current max display order
|
||||
$orderStmt = $conn->prepare("SELECT MAX(display_order) as max_order FROM photos WHERE album_id = ?");
|
||||
$orderStmt->bind_param("i", $album_id);
|
||||
@@ -153,15 +159,17 @@ try {
|
||||
$fileName = $_FILES['photos']['name'][$i];
|
||||
$fileTmpName = $_FILES['photos']['tmp_name'][$i];
|
||||
$fileSize = $_FILES['photos']['size'][$i];
|
||||
$fileMime = mime_content_type($fileTmpName);
|
||||
|
||||
// Validate file
|
||||
if (!in_array($fileMime, $allowedMimes)) {
|
||||
throw new Exception('Invalid file type: ' . $fileName);
|
||||
|
||||
// Validate file extension
|
||||
$ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||
|
||||
if (!in_array($ext, $allowedExtensions)) {
|
||||
throw new Exception('Invalid file type: ' . $fileName . '. Allowed: jpg, jpeg, png, gif, webp');
|
||||
}
|
||||
|
||||
if ($fileSize > $maxSize) {
|
||||
throw new Exception('File too large: ' . $fileName);
|
||||
throw new Exception('File too large: ' . $fileName . ' (max 5MB)');
|
||||
}
|
||||
|
||||
// Generate unique filename
|
||||
|
||||
@@ -43,15 +43,9 @@ if (isset($_FILES['profile_picture']) && $_FILES['profile_picture']['error'] !=
|
||||
$target_dir = $rootPath . "/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();
|
||||
// Ensure upload directory exists
|
||||
if (!file_exists($target_dir)) {
|
||||
mkdir($target_dir, 0777, true);
|
||||
}
|
||||
|
||||
// Move the uploaded file
|
||||
|
||||
Reference in New Issue
Block a user