Mini Shell
<?php
session_start();
$rootPath = realpath(dirname(__FILE__) . '/..');
require_once $rootPath . '/Portal/config/config.php';
require_once $rootPath . '/Portal/include/auth_validate.php';
// Memory and execution time limits
ini_set('memory_limit', '128M');
ini_set('max_execution_time', 300);
set_time_limit(300);
// Error reporting
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Check if user is authenticated
if (!isset($_SESSION['id'])) {
header('Location: login.php');
exit();
}
$User = $_SESSION['id'];
// Fetch user data
$stmt = mysqli_prepare($conn, "SELECT Access_Level, Full_Name FROM admin_accounts WHERE id = ?");
mysqli_stmt_bind_param($stmt, "i", $User);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
if (mysqli_num_rows($result) > 0) {
$rows = mysqli_fetch_assoc($result);
$UserAccessName = $rows['Access_Level'];
$FullName = isset($rows['Full_Name']) ? $rows['Full_Name'] : '';
}
mysqli_stmt_close($stmt);
// File upload configuration
$maxFileSize = 5 * 1024 * 1024; // 5MB
$allowedTypes = ['text/csv', 'application/vnd.ms-excel', 'text/plain', 'application/csv'];
$maxRecords = 1000;
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// Validate inputs
$errors = [];
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
$errors[] = "File upload failed. Error code: " . ($_FILES['file']['error'] ?? 'Unknown');
}
// Validate form fields
$requiredFields = ['Term', 'year'];
foreach ($requiredFields as $field) {
if (empty($_POST[$field])) {
$errors[] = ucfirst(str_replace('_', ' ', $field)) . " is required";
}
}
if (empty($errors)) {
// Sanitize inputs
$Term = mysqli_real_escape_string($conn, $_POST['Term']);
$year = mysqli_real_escape_string($conn, $_POST['year']);
// Validate file
$fileSize = $_FILES['file']['size'];
$fileType = $_FILES['file']['type'];
$tmpName = $_FILES['file']['tmp_name'];
$fileName = $_FILES['file']['name'];
// Check file size
if ($fileSize > $maxFileSize) {
$errors[] = "File size exceeds maximum limit of 5MB";
}
// Check file type (more flexible checking)
$fileExtension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
if (!in_array($fileType, $allowedTypes) && $fileExtension != 'csv') {
$errors[] = "Only CSV files are allowed";
}
if (empty($errors)) {
// Process CSV file from temporary location without saving
$processedCount = 0;
$failedCount = 0;
$duplicateCount = 0;
$successfulRecords = [];
$isFirstRow = true; // Flag to skip header row
$rowNumber = 1; // For tracking row numbers
// Start transaction
mysqli_begin_transaction($conn);
try {
// Open CSV file
$file = fopen($tmpName, 'r');
if ($file !== FALSE) {
ob_start(); // Start output buffering
?>
<html>
<?php include_once 'include/AdminHeader.php'; ?>
<div id="page-wrapper">
<div class="row">
<br><br><br>
</div>
<?php
// Read and process the header row to verify column structure
$headers = fgetcsv($file, 1000, ",");
$expectedHeaders = ['Student_No', 'Full_Name', 'Level', 'Amount_Paid', 'Payment_Mode', 'Reference_No', 'Date_Paid'];
// Optional: Verify headers match expected format
if ($headers !== FALSE) {
// Continue processing data rows
while (($data = fgetcsv($file, 1000, ",")) !== FALSE) {
$rowNumber++;
// Stop if max records reached
if ($processedCount >= $maxRecords) {
$_SESSION['warning'] = "Upload limited to first {$maxRecords} records.";
break;
}
// Validate CSV row has 7 columns
if (count($data) >= 7) {
// Clean and escape data
$Student_No = isset($data[0]) ? mysqli_real_escape_string($conn, trim($data[0])) : '';
$Full_Name = isset($data[1]) ? mysqli_real_escape_string($conn, trim($data[1])) : '';
$Level = isset($data[2]) ? mysqli_real_escape_string($conn, trim($data[2])) : '';
$Amount_Paid = isset($data[3]) ? mysqli_real_escape_string($conn, trim($data[3])) : '';
$Payment_Mode = isset($data[4]) ? mysqli_real_escape_string($conn, trim($data[4])) : '';
$Reference_No = isset($data[5]) ? mysqli_real_escape_string($conn, trim($data[5])) : '';
// Handle date format conversion (from DD-MMM-YY to YYYY-MM-DD)
$Date_Paid_raw = isset($data[6]) ? trim($data[6]) : '';
$Date_Paid = convertDateToMySQL($Date_Paid_raw);
// Basic validation
if (empty($Student_No) || empty($Full_Name) || empty($Level) || empty($Amount_Paid)) {
$failedCount++;
} else {
// Check for duplicate record (using Student_No, Amount, Reference, Term, Year)
$checkDuplicateSql = "SELECT COUNT(*) as count FROM fees_payment
WHERE Student_NO = '$Student_No'
AND Amount = '$Amount_Paid'
AND Reference = '$Reference_No'
AND Term = '$Term'
AND Year = '$year'";
$duplicateResult = mysqli_query($conn, $checkDuplicateSql);
if ($duplicateResult) {
$duplicateRow = mysqli_fetch_assoc($duplicateResult);
if ($duplicateRow['count'] > 0) {
$duplicateCount++;
} else {
// Insert the record (matching database schema)
$insertSql = "INSERT INTO fees_payment
(Student_NO, Student_Name, Amount, Payment_Mode, Date_Paid, Reference, Class_Level, Term, Year, CreatedBy)
VALUES (
'$Student_No',
'$Full_Name',
'$Amount_Paid',
'$Payment_Mode',
" . ($Date_Paid ? "'$Date_Paid'" : "NULL") . ",
'$Reference_No',
'$Level',
'$Term',
'$year',
'$User'
)";
if (mysqli_query($conn, $insertSql)) {
$processedCount++;
// Store successful record for display
$successfulRecords[] = [
'Student_No' => $Student_No,
'Student_Name' => $Full_Name,
'Class_Level' => $Level,
'Amount' => $Amount_Paid,
'Payment_Mode' => $Payment_Mode,
'Reference' => $Reference_No,
'Date_Paid' => $Date_Paid ?: $Date_Paid_raw
];
} else {
$failedCount++;
// Log the error for debugging
error_log("Insert failed for row $rowNumber: " . mysqli_error($conn));
}
}
} else {
$failedCount++;
error_log("Duplicate check failed for row $rowNumber: " . mysqli_error($conn));
}
}
} else {
$failedCount++;
error_log("Row $rowNumber has incorrect number of columns: " . count($data));
}
}
} else {
throw new Exception("Failed to read CSV headers");
}
fclose($file);
// Commit transaction if at least one record was inserted
if ($processedCount > 0) {
mysqli_commit($conn);
} else {
mysqli_rollback($conn);
}
// Display summary
?>
<div class="row">
<div class="col-md-12">
<?php
// Show flash messages
if (file_exists('include/flash_messages.php')) {
include('include/flash_messages.php');
}
?>
<div class="alert alert-info">
<h4>Upload Summary</h4>
<p><strong>File:</strong> <?php echo htmlspecialchars($fileName); ?></p>
<p><strong>Term:</strong> <?php echo htmlspecialchars($Term); ?></p>
<p><strong>Year:</strong> <?php echo htmlspecialchars($year); ?></p>
<hr>
<p>Total Rows Processed: <?php echo ($processedCount + $failedCount + $duplicateCount); ?></p>
<p>Successfully Inserted: <span class="text-success"><?php echo $processedCount; ?></span></p>
<p>Duplicates Skipped: <span class="text-warning"><?php echo $duplicateCount; ?></span></p>
<p>Failed: <span class="text-danger"><?php echo $failedCount; ?></span></p>
<?php if ($processedCount == 0 && ($failedCount + $duplicateCount) > 0): ?>
<hr>
<p><strong>Possible issues:</strong></p>
<ul>
<li>Check if CSV file has correct format (7 columns in this order):
<br><code>Student_No, Full_Name, Level, Amount_Paid, Payment_Mode, Reference_No, Date_Paid</code>
</li>
<li>Date format should be like: 24-Feb-25 (will be converted automatically)</li>
<li>Check if database table "fees_payment" exists with correct columns</li>
<li>Check if you have INSERT permissions on the table</li>
<li>Check PHP error logs for more details</li>
</ul>
<?php endif; ?>
</div>
<?php if (!empty($successfulRecords)): ?>
<h4>Successfully Uploaded Records:</h4>
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>#</th>
<th>Student No</th>
<th>Student Name</th>
<th>Class Level</th>
<th>Amount Paid</th>
<th>Payment Mode</th>
<th>Reference No</th>
<th>Date Paid</th>
<th>Term</th>
<th>Year</th>
</tr>
</thead>
<tbody>
<?php $counter = 1; ?>
<?php foreach ($successfulRecords as $record): ?>
<tr>
<td><?php echo $counter++; ?></td>
<td><?php echo htmlspecialchars($record['Student_No'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($record['Student_Name'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($record['Class_Level'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($record['Amount'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($record['Payment_Mode'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($record['Reference'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($record['Date_Paid'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($Term); ?></td>
<td><?php echo htmlspecialchars($year); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- Back to Admin Portal button -->
<div class="text-center" style="margin-top: 20px; margin-bottom: 20px;">
<a href="AdminPortal.php" class="btn btn-primary">Back Home</a>
<a href="ManageFeesPayments.php" class="btn btn-info">Manage Fees Payments</a>
<a href="javascript:window.print()" class="btn btn-default">Print Report</a>
</div>
<?php else: ?>
<div class="alert alert-warning">
<h4>No Records Uploaded</h4>
<p>No records were successfully uploaded. This could be due to:</p>
<ul>
<li>Empty CSV file</li>
<li>Incorrect CSV format (expected 7 columns)</li>
<li>All records were duplicates</li>
<li>Database connection or permission issues</li>
<li>Date format conversion issues</li>
</ul>
<p>Please check the CSV file format and try again.</p>
</div>
<!-- Back to Fees Payment button -->
<div class="text-center" style="margin-top: 20px; margin-bottom: 20px;">
<a href="ManageFeesPayments.php" class="btn btn-primary">Go Back to Manage Fees</a>
</div>
<?php endif; ?>
</div>
</div>
</div> <!-- Close page-wrapper -->
</html>
<?php
// Set session messages
if ($processedCount > 0) {
$_SESSION['success'] = "Fees payments uploaded successfully! Inserted: {$processedCount}, Duplicates: {$duplicateCount}, Failed: {$failedCount}";
} else {
$_SESSION['failure'] = "No records were uploaded. Total rows processed: " . ($processedCount + $failedCount + $duplicateCount) . ". Please check your CSV file format.";
}
ob_end_flush(); // Flush output buffer
} else {
throw new Exception("Failed to open uploaded file");
}
} catch (Exception $e) {
// Rollback transaction on error
mysqli_rollback($conn);
$_SESSION['failure'] = "Upload failed: " . $e->getMessage();
header('Location: ManageFeesPayments.php');
exit();
}
}
}
// If there were errors, redirect back
if (!empty($errors)) {
$_SESSION['errors'] = $errors;
header('Location: ManageFeesPayments.php');
exit();
}
} else {
// Not a POST request, redirect
header('Location: ManageFeesPayments.php');
exit();
}
/**
* Convert date from DD-MMM-YY format to YYYY-MM-DD for MySQL
* Example: 24-Feb-25 -> 2025-02-24
*/
function convertDateToMySQL($dateString) {
if (empty($dateString)) {
return null;
}
// Remove any extra whitespace
$dateString = trim($dateString);
// Parse the date format like "24-Feb-25"
$parts = explode('-', $dateString);
if (count($parts) == 3) {
$day = $parts[0];
$month = $parts[1];
$year = $parts[2];
// Convert month abbreviation to number
$monthNumbers = [
'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04',
'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08',
'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12'
];
$monthNum = isset($monthNumbers[$month]) ? $monthNumbers[$month] : null;
if ($monthNum && is_numeric($day) && is_numeric($year)) {
// Convert 2-digit year to 4-digit year (25 -> 2025, 24 -> 2024, etc.)
$fullYear = (strlen($year) == 2) ? '20' . $year : $year;
// Ensure day is 2 digits
$day = str_pad($day, 2, '0', STR_PAD_LEFT);
return $fullYear . '-' . $monthNum . '-' . $day;
}
}
// If parsing fails, return null
return null;
}
?>