Sindbad~EG File Manager
<?php
require_once '../../config/config.php';
require_once '../../classes/DirectoryManager.php';
// Load vendor autoload if exists for PhpSpreadsheet
if (file_exists(__DIR__ . '/../../vendor/autoload.php')) {
require_once __DIR__ . '/../../vendor/autoload.php';
}
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\IOFactory;
// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
header('Location: ../../login.php');
exit;
}
$page_title = "Bulk Upload - Standalone Directory";
$directoryManager = new DirectoryManager();
// Handle CSV template download
if (isset($_GET['action']) && $_GET['action'] == 'download_template') {
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="standalone_directory_template.csv"');
$headers = [
'Title', 'First Name', 'Middle Name', 'Last Name', 'Gender',
'Phone', 'Email', 'Address Line', 'City',
'Area ID', 'District ID', 'Assembly ID',
'Occupation', 'Position', 'Notes'
];
echo implode(',', $headers) . "\n";
echo 'Mr.,John,Michael,Doe,Male,0200000000,john.doe@example.com,123 Main St,Accra,1,1,1,Teacher,Board Member,Sample entry';
exit;
}
// Handle Excel template download
if (isset($_GET['action']) && $_GET['action'] == 'download_excel_template') {
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// Headers
$headers = [
'Title', 'First Name', 'Middle Name', 'Last Name', 'Gender',
'Phone', 'Email', 'Address Line', 'City',
'Area ID', 'District ID', 'Assembly ID',
'Occupation', 'Position', 'Notes'
];
$col = 'A';
foreach ($headers as $header) {
$sheet->setCellValue($col . '1', $header);
$sheet->getStyle($col . '1')->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()->setRGB('1E40AF');
$sheet->getStyle($col . '1')->getFont()->setBold(true)->setColor(new \PhpOffice\PhpSpreadsheet\Style\Color('FFFFFF'));
$sheet->getColumnDimension($col)->setAutoSize(true);
$col++;
}
// Sample data
$sheet->setCellValue('A2', 'Mr.');
$sheet->setCellValue('B2', 'John');
$sheet->setCellValue('C2', 'Michael');
$sheet->setCellValue('D2', 'Doe');
$sheet->setCellValue('E2', 'Male');
$sheet->setCellValue('F2', '0200000000');
$sheet->setCellValue('G2', 'john.doe@example.com');
$sheet->setCellValue('H2', '123 Main St');
$sheet->setCellValue('I2', 'Accra');
$sheet->setCellValue('J2', '1');
$sheet->setCellValue('K2', '1');
$sheet->setCellValue('L2', '1');
$sheet->setCellValue('M2', 'Teacher');
$sheet->setCellValue('N2', 'Board Member');
$sheet->setCellValue('O2', 'Sample entry');
$sheet->getStyle('A2:O2')->getFont()->setItalic(true);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="standalone_directory_template.xlsx"');
header('Cache-Control: max-age=0');
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
exit;
}
// Handle file upload
$uploadResults = [];
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['upload_file'])) {
$file = $_FILES['upload_file'];
if ($file['error'] == 0) {
$fileExtension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if ($fileExtension == 'csv') {
// Process CSV
$handle = fopen($file['tmp_name'], 'r');
$headers = fgetcsv($handle);
$rowNum = 1;
while (($row = fgetcsv($handle)) !== false) {
$rowNum++;
try {
$data = [
'title' => $row[0] ?? null,
'first_name' => $row[1] ?? '',
'middle_name' => $row[2] ?? null,
'last_name' => $row[3] ?? '',
'gender' => $row[4] ?? 'Male',
'phone' => $row[5] ?? null,
'email' => $row[6] ?? null,
'address_line' => $row[7] ?? null,
'city' => $row[8] ?? null,
'area_id' => !empty($row[9]) ? $row[9] : null,
'district_id' => !empty($row[10]) ? $row[10] : null,
'assembly_id' => !empty($row[11]) ? $row[11] : null,
'occupation' => $row[12] ?? null,
'position' => $row[13] ?? null,
'notes' => $row[14] ?? null,
'photo' => null,
'created_by' => $_SESSION['user_id']
];
if (empty($data['first_name']) || empty($data['last_name'])) {
$uploadResults[] = [
'row' => $rowNum,
'name' => 'Invalid',
'status' => 'error',
'message' => 'First name and last name are required'
];
continue;
}
if ($directoryManager->addEntry($data)) {
$uploadResults[] = [
'row' => $rowNum,
'name' => trim(($data['title'] ?? '') . ' ' . $data['first_name'] . ' ' . $data['last_name']),
'status' => 'success',
'message' => 'Entry added successfully'
];
} else {
$uploadResults[] = [
'row' => $rowNum,
'name' => trim(($data['title'] ?? '') . ' ' . $data['first_name'] . ' ' . $data['last_name']),
'status' => 'error',
'message' => 'Failed to add entry'
];
}
} catch (Exception $e) {
$uploadResults[] = [
'row' => $rowNum,
'name' => 'Error',
'status' => 'error',
'message' => $e->getMessage()
];
}
}
fclose($handle);
} elseif (in_array($fileExtension, ['xlsx', 'xls'])) {
// Process Excel
$spreadsheet = IOFactory::load($file['tmp_name']);
$sheet = $spreadsheet->getActiveSheet();
$rows = $sheet->toArray();
// Skip header row
array_shift($rows);
$rowNum = 1;
foreach ($rows as $row) {
$rowNum++;
try {
$data = [
'title' => $row[0] ?? null,
'first_name' => $row[1] ?? '',
'middle_name' => $row[2] ?? null,
'last_name' => $row[3] ?? '',
'gender' => $row[4] ?? 'Male',
'phone' => $row[5] ?? null,
'email' => $row[6] ?? null,
'address_line' => $row[7] ?? null,
'city' => $row[8] ?? null,
'area_id' => !empty($row[9]) ? $row[9] : null,
'district_id' => !empty($row[10]) ? $row[10] : null,
'assembly_id' => !empty($row[11]) ? $row[11] : null,
'occupation' => $row[12] ?? null,
'position' => $row[13] ?? null,
'notes' => $row[14] ?? null,
'photo' => null,
'created_by' => $_SESSION['user_id']
];
if (empty($data['first_name']) || empty($data['last_name'])) {
$uploadResults[] = [
'row' => $rowNum,
'name' => 'Invalid',
'status' => 'error',
'message' => 'First name and last name are required'
];
continue;
}
if ($directoryManager->addEntry($data)) {
$uploadResults[] = [
'row' => $rowNum,
'name' => trim(($data['title'] ?? '') . ' ' . $data['first_name'] . ' ' . $data['last_name']),
'status' => 'success',
'message' => 'Entry added successfully'
];
} else {
$uploadResults[] = [
'row' => $rowNum,
'name' => trim(($data['title'] ?? '') . ' ' . $data['first_name'] . ' ' . $data['last_name']),
'status' => 'error',
'message' => 'Failed to add entry'
];
}
} catch (Exception $e) {
$uploadResults[] = [
'row' => $rowNum,
'name' => 'Error',
'status' => 'error',
'message' => $e->getMessage()
];
}
}
} else {
$error = "Invalid file format. Please upload CSV or Excel file.";
}
} else {
$error = "Error uploading file.";
}
}
include '../../includes/header.php';
include '../../includes/sidebar.php';
?>
<!-- Main Content -->
<main class="main-content md:ml-64 pt-16">
<div class="min-h-screen bg-gray-50 py-8">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Header -->
<div class="mb-8">
<div class="gradient-bg rounded-xl shadow-lg p-8 text-white">
<div class="flex items-center justify-between">
<div>
<h1 class="text-3xl font-bold mb-2">Bulk Upload - Standalone Directory</h1>
<p class="text-blue-100">Upload multiple directory entries at once</p>
</div>
<a href="standalone.php" class="bg-white text-primary px-6 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-all duration-300 shadow-md inline-flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
</svg>
Back to List
</a>
</div>
</div>
</div>
<!-- Error Message -->
<?php if (isset($error)): ?>
<div class="bg-red-50 border border-red-200 text-red-800 px-6 py-4 rounded-lg mb-6 flex items-center">
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
<?= $error ?>
</div>
<?php endif; ?>
<!-- Instructions -->
<div class="bg-white rounded-xl shadow-md p-6 mb-6">
<h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center">
<svg class="w-6 h-6 mr-2 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Instructions
</h2>
<ol class="list-decimal list-inside space-y-2 text-gray-700">
<li>Download the template file (CSV or Excel format)</li>
<li>Fill in the directory entry information following the column headers</li>
<li>Save the file</li>
<li>Upload the completed file using the form below</li>
</ol>
<div class="mt-6 p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
<h3 class="font-semibold text-yellow-800 mb-2">Important Notes:</h3>
<ul class="list-disc list-inside space-y-1 text-sm text-yellow-700">
<li><strong>First Name</strong> and <strong>Last Name</strong> are required fields</li>
<li>Gender must be either "Male" or "Female"</li>
<li>Area ID, District ID, and Assembly ID should match existing records in your database</li>
<li>Both CSV and Excel (.xlsx, .xls) file formats are supported</li>
<li>Remove the sample row before uploading your data</li>
</ul>
</div>
</div>
<!-- Download Templates -->
<div class="bg-white rounded-xl shadow-md p-6 mb-6">
<h2 class="text-xl font-bold text-gray-800 mb-4">Download Template</h2>
<div class="flex gap-4">
<a href="?action=download_template" class="btn-gradient-orange px-6 py-3 rounded-lg font-semibold hover:shadow-lg transition-all duration-300 inline-flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
Download CSV Template
</a>
<a href="?action=download_excel_template" class="btn-gradient px-6 py-3 rounded-lg font-semibold hover:shadow-lg transition-all duration-300 inline-flex items-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
Download Excel Template
</a>
</div>
</div>
<!-- Upload Form -->
<div class="bg-white rounded-xl shadow-md p-6 mb-6">
<h2 class="text-xl font-bold text-gray-800 mb-4">Upload File</h2>
<form method="POST" enctype="multipart/form-data" class="space-y-4">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">Select File (CSV or Excel)</label>
<input type="file"
name="upload_file"
accept=".csv,.xlsx,.xls"
required
class="w-full px-4 py-3 border-2 border-dashed border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary">
</div>
<button type="submit" class="btn-gradient px-8 py-3 rounded-lg font-semibold hover:shadow-lg transition-all duration-300">
<svg class="w-5 h-5 inline-block mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/>
</svg>
Upload and Process
</button>
</form>
</div>
<!-- Upload Results -->
<?php if (!empty($uploadResults)): ?>
<div class="bg-white rounded-xl shadow-md overflow-hidden">
<div class="px-6 py-4 bg-gradient-primary text-white">
<h2 class="text-xl font-bold">Upload Results</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gray-50 border-b-2 border-gray-200">
<tr>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase">Row</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase">Name</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase">Status</th>
<th class="px-6 py-3 text-left text-xs font-semibold text-gray-700 uppercase">Message</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<?php foreach ($uploadResults as $result): ?>
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono"><?= $result['row'] ?></td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-semibold"><?= htmlspecialchars($result['name']) ?></td>
<td class="px-6 py-4 whitespace-nowrap">
<?php if ($result['status'] == 'success'): ?>
<span class="px-3 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">Success</span>
<?php else: ?>
<span class="px-3 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800">Error</span>
<?php endif; ?>
</td>
<td class="px-6 py-4 text-sm text-gray-700"><?= htmlspecialchars($result['message']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="px-6 py-4 bg-gray-50 border-t">
<div class="flex items-center justify-between">
<span class="text-sm text-gray-600">
Total: <?= count($uploadResults) ?> |
Success: <span class="text-green-600 font-semibold"><?= count(array_filter($uploadResults, fn($r) => $r['status'] == 'success')) ?></span> |
Errors: <span class="text-red-600 font-semibold"><?= count(array_filter($uploadResults, fn($r) => $r['status'] == 'error')) ?></span>
</span>
<a href="standalone.php" class="btn-gradient px-6 py-2 rounded-lg font-semibold hover:shadow-lg transition-all duration-300">
View Directory
</a>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</main>
<?php include '../../includes/footer.php'; ?>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists