class Database { private static $instance = null; private $pdo; private function __construct() { $dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4'; $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Throw exceptions on errors PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // Fetch rows as associative arrays PDO::ATTR_EMULATE_PREPARES => false, // Disable emulation for better security and performance ]; try { $this->pdo = new PDO($dsn, DB_USER, DB_PASS, $options); } catch (PDOException $e) { // Log the error and terminate error_log('Database connection failed: ' . $e->getMessage()); http_response_code(500); echo json_encode(['error' => 'Database connection failed. Please try again later.']); exit(); } } public static function getInstance() { if (self::$instance === null) { self::$instance = new Database(); } return self::$instance; } public function getConnection() { return $this->pdo; } } // Helper function to get PDO connection function getDbConnection() { return Database::getInstance()->getConnection(); } // Start session if not already started if (session_status() == PHP_SESSION_NONE) { session_start(); } class Auth { private $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } /** * Authenticates a user with username and password. * @param string $username * @param string $password * @return array|false User data on success, false on failure. */ public function loginWithPassword($username, $password) { $stmt = $this->pdo->prepare("SELECT user_id, username, password_hash, role FROM Users WHERE username = ?"); $stmt->execute([$username]); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password_hash'])) { $this->createSession($user['user_id'], $user['username'], $user['role']); return ['user_id' => $user['user_id'], 'username' => $user['username'], 'role' => $user['role']]; } return false; } /** * Authenticates a user with PIN from an approved IP. * @param string $pin * @param string $ip_address * @return array|false User data on success, false on failure. */ public function loginWithPin($pin, $ip_address) { if (!in_array($ip_address, APPROVED_IPS)) { return false; // IP not approved } $stmt = $this->pdo->prepare("SELECT user_id, username, role FROM Users WHERE pin = ?"); $stmt->execute([$pin]); $user = $stmt->fetch(); if ($user) { $this->createSession($user['user_id'], $user['username'], $user['role']); return ['user_id' => $user['user_id'], 'username' => $user['username'], 'role' => $user['role']]; } return false; } private function createSession($userId, $username, $role) { session_regenerate_id(true); // Regenerate session ID for security $_SESSION['user_id'] = $userId; $_SESSION['username'] = $username; $_SESSION['role'] = $role; $_SESSION['logged_in'] = true; } /** * Checks if a user is currently authenticated. * @return bool */ public function isAuthenticated() { return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true; } /** * Gets the current authenticated user's data. * @return array|null User data or null if not authenticated. */ public function getCurrentUser() { if ($this->isAuthenticated()) { return [ 'user_id' => $_SESSION['user_id'], 'username' => $_SESSION['username'], 'role' => $_SESSION['role'] ]; } return null; } /** * Checks if the current user has the required role. * @param string $requiredRole * @return bool */ public function hasRole($requiredRole) { return $this->isAuthenticated() && $_SESSION['role'] === $requiredRole; } /** * Logs out the current user. */ public function logout() { $_SESSION = array(); // Clear all session variables session_destroy(); // Destroy the session setcookie(session_name(), '', time() - 3600, '/'); // Clear session cookie } } class AuditLogger { private $pdo; private $auth; public function __construct(PDO $pdo, Auth $auth) { $this->pdo = $pdo; $this->auth = $auth; } /** * Logs an audit event. * @param string $actionType e.g., 'INSERT', 'UPDATE', 'DELETE', 'LOGIN' * @param string $tableName * @param int|null $recordId ID of the affected record * @param array|null $oldValue Old data (associative array) * @param array|null $newValue New data (associative array) */ public function logEvent($actionType, $tableName, $recordId = null, $oldValue = null, $newValue = null) { $user = $this->auth->getCurrentUser(); $userId = $user ? $user['user_id'] : null; $ipAddress = $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN'; $stmt = $this->pdo->prepare(" INSERT INTO AuditLog (user_id, action_type, table_name, record_id, old_value, new_value, ip_address) VALUES (?, ?, ?, ?, ?, ?, ?) "); $stmt->execute([ $userId, $actionType, $tableName, $recordId, $oldValue ? json_encode($oldValue) : null, $newValue ? json_encode($newValue) : null, $ipAddress ]); } } /** * Sends a JSON response and exits. * @param array $data The data to encode as JSON. * @param int $statusCode HTTP status code. */ function sendJsonResponse($data, $statusCode = 200) { header('Content-Type: application/json'); http_response_code($statusCode); echo json_encode($data); exit(); } /** * Checks if the request method matches the expected method. * @param string $method Expected HTTP method (e.g., 'GET', 'POST', 'PUT', 'DELETE'). */ function requireMethod($method) { if ($_SERVER['REQUEST_METHOD'] !== $method) { sendJsonResponse(['error' => 'Method Not Allowed'], 405); } } /** * Gets JSON input from the request body. * @return array Decoded JSON data. */ function getJsonInput() { $input = file_get_contents('php://input'); $data = json_decode($input, true); if (json_last_error() !== JSON_ERROR_NONE) { sendJsonResponse(['error' => 'Invalid JSON input'], 400); } return $data; } /** * Fetches a single record by ID from a table. * @param PDO $pdo * @param string $tableName * @param string $idColumnName * @param int $id * @return array|false The fetched record or false if not found. */ function getRecordById(PDO $pdo, $tableName, $idColumnName, $id) { $stmt = $pdo->prepare("SELECT * FROM {$tableName} WHERE {$idColumnName} = ?"); $stmt->execute([$id]); return $stmt->fetch(); }
Fatal error: Uncaught Error: Call to undefined function getDbConnection() in /home/nerhcwjs/public_html/services/index.php:10 Stack trace: #0 {main} thrown in /home/nerhcwjs/public_html/services/index.php on line 10