154 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
// ─── DB CONFIG ─────────────────────────────────────────────────
 | 
						|
$dbHost = 'localhost';
 | 
						|
$dbPort = '5432';
 | 
						|
$dbName = 'af585fp_db';
 | 
						|
$dbUser = 'database_user';
 | 
						|
$dbPass = 'password_database';
 | 
						|
// ────────────────────────────────────────────────────────────────
 | 
						|
 | 
						|
$dsn = "pgsql:host=$dbHost;port=$dbPort;dbname=$dbName";
 | 
						|
try {
 | 
						|
    $pdo = new PDO($dsn, $dbUser, $dbPass, [
 | 
						|
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
 | 
						|
    ]);
 | 
						|
    // Auto-migration: if the table does not exist, create it
 | 
						|
    $pdo->exec(<<<'SQL'
 | 
						|
CREATE TABLE IF NOT EXISTS visitors (
 | 
						|
    id SERIAL PRIMARY KEY,
 | 
						|
    visited_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
 | 
						|
);
 | 
						|
SQL
 | 
						|
    );
 | 
						|
} catch (Exception $e) {
 | 
						|
    die("Database connection or migration failed: " . $e->getMessage());
 | 
						|
}
 | 
						|
 | 
						|
// Insert a row then count
 | 
						|
$pdo->exec("INSERT INTO visitors DEFAULT VALUES");
 | 
						|
$count = $pdo->query("SELECT COUNT(*) FROM visitors")->fetchColumn();
 | 
						|
?>
 | 
						|
<!DOCTYPE html>
 | 
						|
<html lang="en">
 | 
						|
<head>
 | 
						|
  <meta charset="utf-8">
 | 
						|
  <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
						|
  <title>Visit Counter</title>
 | 
						|
  <style>
 | 
						|
    /* Import Google Fonts */
 | 
						|
    @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600&display=swap');
 | 
						|
 | 
						|
    :root {
 | 
						|
      --bg-light: #f0f4f8;
 | 
						|
      --bg-dark: #1a1a2e;
 | 
						|
      --card-bg-light: #ffffff;
 | 
						|
      --card-bg-dark: rgba(26,26,46,0.8);
 | 
						|
      --primary: #2e86de;
 | 
						|
      --text-light: #333333;
 | 
						|
      --text-dark: #eaeaea;
 | 
						|
    }
 | 
						|
 | 
						|
    * {
 | 
						|
      box-sizing: border-box;
 | 
						|
      margin: 0;
 | 
						|
      padding: 0;
 | 
						|
    }
 | 
						|
 | 
						|
    body {
 | 
						|
      font-family: 'Montserrat', sans-serif;
 | 
						|
      display: flex;
 | 
						|
      justify-content: center;
 | 
						|
      align-items: center;
 | 
						|
      height: 100vh;
 | 
						|
      background: var(--bg-light);
 | 
						|
      transition: background 0.3s ease;
 | 
						|
      color: var(--text-light);
 | 
						|
    }
 | 
						|
    body.dark {
 | 
						|
      background: var(--bg-dark);
 | 
						|
      color: var(--text-dark);
 | 
						|
    }
 | 
						|
 | 
						|
    .card {
 | 
						|
      background: var(--card-bg-light);
 | 
						|
      padding: 2rem;
 | 
						|
      border-radius: 1rem;
 | 
						|
      box-shadow: 0 8px 24px rgba(0,0,0,0.1);
 | 
						|
      text-align: center;
 | 
						|
      width: 90%;
 | 
						|
      max-width: 400px;
 | 
						|
      backdrop-filter: blur(10px);
 | 
						|
      transition: background 0.3s ease, box-shadow 0.3s ease;
 | 
						|
    }
 | 
						|
    body.dark .card {
 | 
						|
      background: var(--card-bg-dark);
 | 
						|
      box-shadow: 0 8px 24px rgba(0,0,0,0.5);
 | 
						|
    }
 | 
						|
 | 
						|
    .controls {
 | 
						|
      display: flex;
 | 
						|
      justify-content: space-between;
 | 
						|
      margin-bottom: 1.5rem;
 | 
						|
    }
 | 
						|
 | 
						|
    .controls button {
 | 
						|
      background: var(--primary);
 | 
						|
      border: none;
 | 
						|
      color: #fff;
 | 
						|
      padding: 0.5rem 1rem;
 | 
						|
      border-radius: 0.5rem;
 | 
						|
      font-size: 1rem;
 | 
						|
      cursor: pointer;
 | 
						|
      box-shadow: 0 4px 12px rgba(0,0,0,0.1);
 | 
						|
      transition: transform 0.2s ease, box-shadow 0.2s ease;
 | 
						|
    }
 | 
						|
    .controls button:hover {
 | 
						|
      transform: translateY(-2px);
 | 
						|
      box-shadow: 0 6px 16px rgba(0,0,0,0.15);
 | 
						|
    }
 | 
						|
 | 
						|
    h1 {
 | 
						|
      font-size: 2rem;
 | 
						|
      margin-bottom: 1rem;
 | 
						|
    }
 | 
						|
 | 
						|
    p {
 | 
						|
      font-size: 1.25rem;
 | 
						|
    }
 | 
						|
 | 
						|
    strong {
 | 
						|
      color: var(--primary);
 | 
						|
    }
 | 
						|
  </style>
 | 
						|
</head>
 | 
						|
<body>
 | 
						|
  <div class="card">
 | 
						|
    <div class="controls">
 | 
						|
      <button id="refreshBtn">↻ Refresh</button>
 | 
						|
      <button id="themeToggle">🌙</button>
 | 
						|
    </div>
 | 
						|
    <h1>Visit Counter</h1>
 | 
						|
    <p>You are visitor # <strong><?= htmlspecialchars($count) ?></strong></p>
 | 
						|
  </div>
 | 
						|
  <script>
 | 
						|
    // Refresh the page without submitting the count twice
 | 
						|
    document.getElementById('refreshBtn').addEventListener('click', () => {
 | 
						|
      location.reload();
 | 
						|
    });
 | 
						|
    // Handling light/dark theme
 | 
						|
    const toggle = document.getElementById('themeToggle');
 | 
						|
    const applyTheme = (dark) => {
 | 
						|
      document.body.classList.toggle('dark', dark);
 | 
						|
      toggle.textContent = dark ? '☀️' : '🌙';
 | 
						|
      localStorage.setItem('darkMode', dark);
 | 
						|
    };
 | 
						|
    toggle.addEventListener('click', () => {
 | 
						|
      applyTheme(!document.body.classList.contains('dark'));
 | 
						|
    });
 | 
						|
    // Initialization
 | 
						|
    const darkMode = localStorage.getItem('darkMode') === 'true';
 | 
						|
    applyTheme(darkMode);
 | 
						|
  </script>
 | 
						|
</body>
 | 
						|
</html>
 |