Sindbad~EG File Manager
<?php
require_once '../../config/config.php';
checkLogin();
$pageTitle = "Bulk Update Members - " . APP_NAME;
$db = Database::getInstance()->getConnection();
$success = '';
$error = '';
// Handle template downloads
if (isset($_GET['download_template'])) {
$format = $_GET['download_template'];
// Get member fields for template
$fields = [
'id', 'title', 'first_name', 'middle_name', 'last_name', 'gender', 'date_of_birth',
'place_of_birth', 'phone', 'email', 'member_type', 'marital_status', 'address_line1',
'gps_address', 'street_name', 'city', 'hometown', 'parent_name', 'parent_relationship',
'occupation', 'level_of_education', 'water_baptism', 'date_of_baptism', 'place_of_baptism',
'officiating_minister_baptism', 'holyghost_baptism', 'date_of_holyspirit_baptism',
'communicant', 'dedicated', 'dedication_date'
];
if ($format === 'csv') {
// CSV Download
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=bulk_update_template_' . date('Ymd') . '.csv');
$output = fopen('php://output', 'w');
fputcsv($output, $fields);
// Add one sample row
$sampleRow = array_fill(0, count($fields), '');
$sampleRow[0] = '1'; // id
$sampleRow[2] = 'John'; // first_name
$sampleRow[4] = 'Doe'; // last_name
fputcsv($output, $sampleRow);
fclose($output);
exit();
} elseif ($format === 'excel') {
// Excel Download
require_once '../../vendor/autoload.php';
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// Header row with styling
$col = 'A';
foreach ($fields as $field) {
$sheet->setCellValue($col . '1', $field);
$sheet->getStyle($col . '1')->applyFromArray([
'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']],
'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => '1E40AF']]
]);
$sheet->getColumnDimension($col)->setAutoSize(true);
$col++;
}
// Sample row
$sheet->setCellValue('A2', '1');
$sheet->setCellValue('C2', 'John');
$sheet->setCellValue('E2', 'Doe');
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename=bulk_update_template_' . date('Ymd') . '.xlsx');
$writer->save('php://output');
exit();
}
}
// Handle file upload
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['update_file'])) {
try {
$file = $_FILES['update_file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
throw new Exception("File upload error");
}
$fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if ($fileExtension === 'csv') {
// Process CSV file
$handle = fopen($file['tmp_name'], 'r');
$headers = fgetcsv($handle);
$updateResults = [];
$row = 1;
while (($data = fgetcsv($handle)) !== false) {
$row++;
try {
$rowData = array_combine($headers, $data);
// Must have member ID to update
if (empty($rowData['id'])) {
$updateResults[] = [
'row' => $row,
'status' => 'error',
'message' => 'Missing member ID'
];
continue;
}
$memberId = $rowData['id'];
// Build update query dynamically based on provided fields
$updateFields = [];
$params = ['id' => $memberId];
$allowedFields = [
'title', 'first_name', 'middle_name', 'last_name', 'gender',
'date_of_birth', 'place_of_birth', 'phone', 'email',
'member_type', 'marital_status', 'address_line1', 'gps_address',
'hometown', 'street_name', 'city', 'parent_name', 'parent_relationship',
'occupation', 'level_of_education', 'water_baptism', 'date_of_baptism',
'place_of_baptism', 'officiating_minister_baptism', 'holyghost_baptism',
'date_of_holyspirit_baptism', 'communicant', 'dedicated', 'dedication_date'
];
foreach ($allowedFields as $field) {
if (isset($rowData[$field]) && $rowData[$field] !== '') {
$updateFields[] = "$field = :$field";
$params[$field] = $rowData[$field];
}
}
if (empty($updateFields)) {
$updateResults[] = [
'row' => $row,
'member_id' => $memberId,
'status' => 'warning',
'message' => 'No fields to update'
];
continue;
}
$sql = "UPDATE members SET " . implode(', ', $updateFields) . " WHERE id = :id";
$stmt = $db->prepare($sql);
$stmt->execute($params);
// Get member name
$nameStmt = $db->prepare("SELECT first_name, last_name FROM members WHERE id = :id");
$nameStmt->execute(['id' => $memberId]);
$member = $nameStmt->fetch();
$updateResults[] = [
'row' => $row,
'member_id' => $memberId,
'member_name' => $member ? $member['first_name'] . ' ' . $member['last_name'] : 'Unknown',
'status' => 'success',
'message' => count($updateFields) . ' fields updated'
];
} catch (Exception $e) {
$updateResults[] = [
'row' => $row,
'status' => 'error',
'message' => $e->getMessage()
];
}
}
fclose($handle);
$_SESSION['update_results'] = $updateResults;
} elseif (in_array($fileExtension, ['xlsx', 'xls'])) {
// Process Excel file
require_once '../../vendor/autoload.php';
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($file['tmp_name']);
$worksheet = $spreadsheet->getActiveSheet();
$rows = $worksheet->toArray();
$headers = array_shift($rows);
$updateResults = [];
$rowNum = 1;
foreach ($rows as $data) {
$rowNum++;
try {
$rowData = array_combine($headers, $data);
if (empty($rowData['id'])) {
$updateResults[] = [
'row' => $rowNum,
'status' => 'error',
'message' => 'Missing member ID'
];
continue;
}
$memberId = $rowData['id'];
$updateFields = [];
$params = ['id' => $memberId];
$allowedFields = [
'title', 'first_name', 'middle_name', 'last_name', 'gender',
'date_of_birth', 'place_of_birth', 'phone', 'email',
'member_type', 'marital_status', 'address_line1', 'gps_address',
'hometown', 'street_name', 'city', 'parent_name', 'parent_relationship',
'occupation', 'level_of_education', 'water_baptism', 'date_of_baptism',
'place_of_baptism', 'officiating_minister_baptism', 'holyghost_baptism',
'date_of_holyspirit_baptism', 'communicant', 'dedicated', 'dedication_date'
];
foreach ($allowedFields as $field) {
if (isset($rowData[$field]) && $rowData[$field] !== null && $rowData[$field] !== '') {
$updateFields[] = "$field = :$field";
$params[$field] = $rowData[$field];
}
}
if (empty($updateFields)) {
$updateResults[] = [
'row' => $rowNum,
'member_id' => $memberId,
'status' => 'warning',
'message' => 'No fields to update'
];
continue;
}
$sql = "UPDATE members SET " . implode(', ', $updateFields) . " WHERE id = :id";
$stmt = $db->prepare($sql);
$stmt->execute($params);
$nameStmt = $db->prepare("SELECT first_name, last_name FROM members WHERE id = :id");
$nameStmt->execute(['id' => $memberId]);
$member = $nameStmt->fetch();
$updateResults[] = [
'row' => $rowNum,
'member_id' => $memberId,
'member_name' => $member ? $member['first_name'] . ' ' . $member['last_name'] : 'Unknown',
'status' => 'success',
'message' => count($updateFields) . ' fields updated'
];
} catch (Exception $e) {
$updateResults[] = [
'row' => $rowNum,
'status' => 'error',
'message' => $e->getMessage()
];
}
}
$_SESSION['update_results'] = $updateResults;
} else {
throw new Exception("Unsupported file format. Please upload CSV or Excel file.");
}
$success = "Bulk update completed! " . count($updateResults) . " records processed.";
} catch (Exception $e) {
$error = "Error processing file: " . $e->getMessage();
}
}
$updateResults = $_SESSION['update_results'] ?? [];
include '../../includes/header.php';
?>
<?php include '../../includes/sidebar.php'; ?>
<!-- Main Content -->
<main class="flex-1 md:ml-64 mt-16">
<div class="container mx-auto px-4 py-8">
<div class="max-w-6xl mx-auto">
<div class="mb-6 flex justify-between items-center">
<div>
<h1 class="text-3xl font-bold text-gray-800">
<i class="fas fa-file-upload mr-2 text-blue-500"></i>Bulk Update Members
</h1>
<p class="text-gray-600 mt-2">Update multiple member records using CSV or Excel file</p>
</div>
<a href="index.php" class="bg-gray-500 text-white px-4 py-2 rounded-lg hover:bg-gray-600 transition">
<i class="fas fa-arrow-left mr-2"></i>Back to Members
</a>
</div>
<?php if ($success): ?>
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded-lg mb-6">
<i class="fas fa-check-circle mr-2"></i><?php echo $success; ?>
</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded-lg mb-6">
<i class="fas fa-exclamation-circle mr-2"></i><?php echo $error; ?>
</div>
<?php endif; ?>
<!-- Instructions -->
<div class="bg-blue-50 rounded-xl shadow-lg p-6 mb-6">
<h3 class="text-lg font-semibold text-blue-800 mb-4">
<i class="fas fa-info-circle mr-2"></i>How to Use Bulk Update
</h3>
<ol class="space-y-2 text-blue-700">
<li class="flex items-start">
<span class="font-bold mr-2">1.</span>
<span>Download the update template below (includes current member data)</span>
</li>
<li class="flex items-start">
<span class="font-bold mr-2">2.</span>
<span>Edit only the fields you want to update. <strong>Do not modify the 'id' column!</strong></span>
</li>
<li class="flex items-start">
<span class="font-bold mr-2">3.</span>
<span>Upload the modified file below</span>
</li>
<li class="flex items-start">
<span class="font-bold mr-2">4.</span>
<span>Review the results and verify changes</span>
</li>
</ol>
</div>
<!-- Download Template -->
<div class="bg-white rounded-xl shadow-lg p-6 mb-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4">
<i class="fas fa-download mr-2"></i>Step 1: Download Template with Current Data
</h3>
<p class="text-gray-600 mb-4">Download a template file containing current member data that you can update:</p>
<div class="flex gap-4">
<a href="?download_template=csv"
class="bg-gradient-to-r from-orange-500 to-yellow-500 text-white px-6 py-3 rounded-lg hover:shadow-lg transition">
<i class="fas fa-file-csv mr-2"></i>Download CSV Template
</a>
<a href="?download_template=excel"
class="bg-gradient-to-r from-blue-500 to-blue-700 text-white px-6 py-3 rounded-lg hover:shadow-lg transition">
<i class="fas fa-file-excel mr-2"></i>Download Excel Template
</a>
</div>
</div>
<!-- Upload Form -->
<div class="bg-white rounded-xl shadow-lg p-6 mb-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4">
<i class="fas fa-upload mr-2"></i>Step 2: Upload Updated File
</h3>
<form method="POST" enctype="multipart/form-data" class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">
Select File (CSV or Excel)
</label>
<input type="file" name="update_file" accept=".csv,.xlsx,.xls" required
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500">
</div>
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
<h4 class="font-semibold text-yellow-800 mb-2">
<i class="fas fa-exclamation-triangle mr-2"></i>Important Notes
</h4>
<ul class="text-sm text-yellow-700 space-y-1">
<li>• The 'id' column is required and must not be modified</li>
<li>• Only include members you want to update</li>
<li>• Empty cells will not update that field</li>
<li>• Boolean fields: use 1 for Yes, 0 for No</li>
<li>• Date format: YYYY-MM-DD</li>
</ul>
</div>
<div class="flex justify-center">
<button type="submit" class="bg-blue-500 text-white px-8 py-3 rounded-lg hover:bg-blue-600 transition">
<i class="fas fa-upload mr-2"></i>Upload & Update Members
</button>
</div>
</form>
</div>
<!-- Results -->
<?php if (!empty($updateResults)): ?>
<div class="bg-white rounded-xl shadow-lg p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold text-gray-800">
<i class="fas fa-list-check mr-2"></i>Update Results
</h3>
<button onclick="location.reload()" class="text-gray-600 hover:text-gray-800">
<i class="fas fa-times mr-2"></i>Clear Results
</button>
</div>
<div class="mb-4 grid grid-cols-3 gap-4">
<div class="bg-green-50 p-4 rounded-lg">
<div class="text-green-600 font-bold text-2xl">
<?php echo count(array_filter($updateResults, fn($r) => $r['status'] == 'success')); ?>
</div>
<div class="text-green-700 text-sm">Successful Updates</div>
</div>
<div class="bg-yellow-50 p-4 rounded-lg">
<div class="text-yellow-600 font-bold text-2xl">
<?php echo count(array_filter($updateResults, fn($r) => $r['status'] == 'warning')); ?>
</div>
<div class="text-yellow-700 text-sm">Warnings</div>
</div>
<div class="bg-red-50 p-4 rounded-lg">
<div class="text-red-600 font-bold text-2xl">
<?php echo count(array_filter($updateResults, fn($r) => $r['status'] == 'error')); ?>
</div>
<div class="text-red-700 text-sm">Errors</div>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full bg-white border border-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Row</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Member</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Status</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Message</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<?php foreach ($updateResults as $result): ?>
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<?php echo $result['row']; ?>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<?php echo $result['member_name'] ?? ($result['member_id'] ?? 'N/A'); ?>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<?php if ($result['status'] == 'success'): ?>
<span class="px-2 py-1 text-xs font-medium rounded-full bg-green-100 text-green-800">Success</span>
<?php elseif ($result['status'] == 'warning'): ?>
<span class="px-2 py-1 text-xs font-medium rounded-full bg-yellow-100 text-yellow-800">Warning</span>
<?php else: ?>
<span class="px-2 py-1 text-xs font-medium rounded-full bg-red-100 text-red-800">Error</span>
<?php endif; ?>
</td>
<td class="px-6 py-4 text-sm text-gray-600">
<?php echo htmlspecialchars($result['message']); ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
</div>
</div>
</main>
<?php include '../../includes/footer.php'; ?>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists