Sindbad~EG File Manager
<?php
/**
* Application Configuration
* Church Membership System
*/
// Start session if not already started (only if headers not sent)
if (session_status() === PHP_SESSION_NONE && !headers_sent()) {
session_start();
}
// Timezone
date_default_timezone_set('UTC');
// Application Settings
define('APP_NAME', 'Church Membership System');
define('APP_VERSION', '1.0.0');
// Auto-detect BASE_URL for portability
// Since config.php is in /config/ directory, go up one level to get app root
$appRoot = dirname(__DIR__);
$documentRoot = $_SERVER['DOCUMENT_ROOT'] ?? '';
// Calculate relative path from document root to app root
if ($documentRoot && strpos($appRoot, $documentRoot) === 0) {
$relativePath = str_replace('\\', '/', substr($appRoot, strlen($documentRoot)));
$relativePath = '/' . trim($relativePath, '/') . '/';
} else {
// Fallback: try to detect from SCRIPT_NAME
$relativePath = '/';
if (isset($_SERVER['SCRIPT_NAME'])) {
$scriptPath = dirname($_SERVER['SCRIPT_NAME']);
// Remove /modules, /includes, /members etc. to get to root
$scriptPath = preg_replace('#/(modules|includes|members|api|classes|config)/.*$#', '', $scriptPath);
$relativePath = rtrim($scriptPath, '/') . '/';
}
}
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)) ? "https://" : "http://";
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
define('BASE_URL', $protocol . $host . $relativePath);
define('UPLOAD_PATH', __DIR__ . '/../uploads/');
define('MAX_UPLOAD_SIZE', 5242880); // 5MB
// Security
define('HASH_ALGO', PASSWORD_BCRYPT);
define('SESSION_LIFETIME', 3600); // 1 hour
// Pagination
define('RECORDS_PER_PAGE', 25);
// Include database configuration
require_once __DIR__ . '/database.php';
// Autoload classes
spl_autoload_register(function ($class) {
$file = __DIR__ . '/../classes/' . $class . '.php';
if (file_exists($file)) {
require_once $file;
}
});
// Helper Functions
function sanitize($data) {
return htmlspecialchars(strip_tags(trim($data)), ENT_QUOTES, 'UTF-8');
}
function redirect($url) {
header("Location: " . BASE_URL . $url);
exit();
}
function isLoggedIn() {
return isset($_SESSION['user_id']) && !empty($_SESSION['user_id']);
}
function isSuperuser() {
return isset($_SESSION['is_superuser']) && $_SESSION['is_superuser'] === true;
}
function isAreaAdmin() {
return getUserAccessLevel() === 'area' || isSuperuser();
}
function isDistrictAdmin() {
return getUserAccessLevel() === 'district' || isAreaAdmin();
}
function isAssemblyAdmin() {
return getUserAccessLevel() === 'assembly' || isDistrictAdmin();
}
function checkLogin() {
if (!isLoggedIn()) {
redirect('login.php');
}
}
function getAccessLevel() {
return $_SESSION['access_level'] ?? null;
}
function canAccess($level) {
$accessHierarchy = ['assembly' => 1, 'district' => 2, 'area' => 3, 'superuser' => 4];
$userLevel = $accessHierarchy[getAccessLevel()] ?? 0;
$requiredLevel = $accessHierarchy[$level] ?? 0;
return $userLevel >= $requiredLevel || isSuperuser();
}
function checkAccess($requiredLevel, $redirectUrl = 'dashboard.php') {
if (!canAccess($requiredLevel)) {
$_SESSION['error'] = 'You do not have permission to access this resource.';
redirect($redirectUrl);
}
}
function canAccessModule($moduleName) {
try {
$db = Database::getInstance()->getConnection();
$userAccessLevel = getUserAccessLevel();
// Check if module exists and is active, and if user's access level is enabled
$stmt = $db->prepare("
SELECT mal.is_enabled
FROM module_management m
INNER JOIN module_access_levels mal ON m.id = mal.module_id
WHERE m.module_name = :module_name
AND m.is_active = 1
AND mal.access_level = :access_level
");
$stmt->execute([
'module_name' => $moduleName,
'access_level' => $userAccessLevel
]);
$result = $stmt->fetch();
if (!$result) {
return false;
}
return (bool)$result['is_enabled'];
} catch (Exception $e) {
error_log("canAccessModule error: " . $e->getMessage());
return false;
}
}
function formatDate($date, $format = 'Y-m-d') {
if (empty($date)) return '';
return date($format, strtotime($date));
}
function timeAgo($datetime) {
$timestamp = strtotime($datetime);
$difference = time() - $timestamp;
$periods = [
'year' => 31536000,
'month' => 2592000,
'week' => 604800,
'day' => 86400,
'hour' => 3600,
'minute' => 60,
'second' => 1
];
foreach ($periods as $key => $value) {
if ($difference >= $value) {
$time = floor($difference / $value);
return $time . ' ' . $key . ($time > 1 ? 's' : '') . ' ago';
}
}
return 'Just now';
}
function generateMemberId($areaCode, $districtCode, $assemblyCode) {
$timestamp = time();
$random = mt_rand(100, 999);
return strtoupper($areaCode . $districtCode . $assemblyCode . $timestamp . $random);
}
function sendJsonResponse($success, $message = '', $data = []) {
header('Content-Type: application/json');
echo json_encode([
'success' => $success,
'message' => $message,
'data' => $data
]);
exit();
}
function getCurrentUserName() {
return $_SESSION['full_name'] ?? $_SESSION['username'] ?? 'User';
}
function getCurrentUserPhoto() {
return !empty($_SESSION['profile_photo']) ? BASE_URL . 'uploads/profiles/' . $_SESSION['profile_photo'] : BASE_URL . 'assets/images/default-avatar.png';
}
function getUserAccessLevel() {
return $_SESSION['access_level'] ?? 'assembly';
}
function getUserAreaId() {
return $_SESSION['area_id'] ?? null;
}
function getUserDistrictId() {
return $_SESSION['district_id'] ?? null;
}
function getUserAssemblyId() {
return $_SESSION['assembly_id'] ?? null;
}
/**
* Apply access level restrictions to SQL query
* Returns array with 'where' clause and 'params'
*
* @param string $tableAlias The table alias (e.g., 'm' for members)
* @param array $options Configuration options:
* - 'area_column' => column name for area_id (default: 'area_id')
* - 'district_column' => column name for district_id (default: 'district_id')
* - 'assembly_column' => column name for assembly_id (default: 'assembly_id')
* - 'bypass_superuser' => if true, superusers also get filtered (default: false)
* @return array ['where' => string, 'params' => array]
*/
function applyAccessLevelFilter($tableAlias = '', $options = []) {
// Default options
$defaults = [
'area_column' => 'area_id',
'district_column' => 'district_id',
'assembly_column' => 'assembly_id',
'bypass_superuser' => false
];
$options = array_merge($defaults, $options);
// Superusers see everything (unless bypassed)
if (!$options['bypass_superuser'] && isSuperuser()) {
return ['where' => '', 'params' => []];
}
$accessLevel = getUserAccessLevel();
$prefix = $tableAlias ? $tableAlias . '.' : '';
$where = '';
$params = [];
switch ($accessLevel) {
case 'assembly':
$assemblyId = getUserAssemblyId();
if ($assemblyId) {
$where = " AND {$prefix}{$options['assembly_column']} = :access_assembly_id";
$params['access_assembly_id'] = $assemblyId;
}
break;
case 'district':
$districtId = getUserDistrictId();
if ($districtId) {
$where = " AND {$prefix}{$options['district_column']} = :access_district_id";
$params['access_district_id'] = $districtId;
}
break;
case 'area':
$areaId = getUserAreaId();
if ($areaId) {
$where = " AND {$prefix}{$options['area_column']} = :access_area_id";
$params['access_area_id'] = $areaId;
}
break;
}
return ['where' => $where, 'params' => $params];
}
/**
* Get WHERE clause for access level filtering
* Quick helper that returns just the WHERE string
*/
function getAccessLevelWhere($tableAlias = '', $options = []) {
$filter = applyAccessLevelFilter($tableAlias, $options);
return $filter['where'];
}
/**
* Get params for access level filtering
* Quick helper that returns just the params array
*/
function getAccessLevelParams($tableAlias = '', $options = []) {
$filter = applyAccessLevelFilter($tableAlias, $options);
return $filter['params'];
}
/**
* Check if current user can view specific record based on location
*/
function canAccessRecord($recordAreaId, $recordDistrictId, $recordAssemblyId) {
if (isSuperuser()) {
return true;
}
$accessLevel = getUserAccessLevel();
switch ($accessLevel) {
case 'assembly':
return $recordAssemblyId == getUserAssemblyId();
case 'district':
return $recordDistrictId == getUserDistrictId();
case 'area':
return $recordAreaId == getUserAreaId();
default:
return false;
}
}
/**
* Get user's access scope description
*/
function getUserAccessScope() {
if (isSuperuser()) {
return 'All Areas';
}
$db = Database::getInstance()->getConnection();
$accessLevel = getUserAccessLevel();
try {
switch ($accessLevel) {
case 'assembly':
$assemblyId = getUserAssemblyId();
if ($assemblyId) {
$stmt = $db->prepare("SELECT assembly_name FROM assemblies WHERE id = :id");
$stmt->execute(['id' => $assemblyId]);
$result = $stmt->fetch();
return $result ? $result['assembly_name'] . ' Assembly' : 'Assembly Level';
}
return 'Assembly Level';
case 'district':
$districtId = getUserDistrictId();
if ($districtId) {
$stmt = $db->prepare("SELECT district_name FROM districts WHERE id = :id");
$stmt->execute(['id' => $districtId]);
$result = $stmt->fetch();
return $result ? $result['district_name'] . ' District' : 'District Level';
}
return 'District Level';
case 'area':
$areaId = getUserAreaId();
if ($areaId) {
$stmt = $db->prepare("SELECT area_name FROM areas WHERE id = :id");
$stmt->execute(['id' => $areaId]);
$result = $stmt->fetch();
return $result ? $result['area_name'] . ' Area' : 'Area Level';
}
return 'Area Level';
default:
return 'Unknown';
}
} catch (Exception $e) {
return ucfirst($accessLevel) . ' Level';
}
}
/**
* Get display badge for user access level
*/
function getUserAccessBadge() {
$level = getUserAccessLevel();
$scope = getUserAccessScope();
$badges = [
'superuser' => '<span class="px-3 py-1 rounded-full text-xs font-semibold bg-gradient-to-r from-purple-500 to-pink-500 text-white"><i class="fas fa-crown mr-1"></i>Superuser - All Access</span>',
'area' => '<span class="px-3 py-1 rounded-full text-xs font-semibold bg-blue-100 text-blue-800"><i class="fas fa-map mr-1"></i>' . htmlspecialchars($scope) . '</span>',
'district' => '<span class="px-3 py-1 rounded-full text-xs font-semibold bg-green-100 text-green-800"><i class="fas fa-map-marked-alt mr-1"></i>' . htmlspecialchars($scope) . '</span>',
'assembly' => '<span class="px-3 py-1 rounded-full text-xs font-semibold bg-yellow-100 text-yellow-800"><i class="fas fa-church mr-1"></i>' . htmlspecialchars($scope) . '</span>'
];
if (isSuperuser()) {
return $badges['superuser'];
}
return $badges[$level] ?? '<span class="px-3 py-1 rounded-full text-xs font-semibold bg-gray-100 text-gray-800">' . htmlspecialchars($scope) . '</span>';
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists