Sebelum coding, pahami dulu alur login yang akan kita buat:
password_hash(). Untuk verifikasi, kita pakai password_verify() yang membandingkan password asli dengan hash.
password_hash('admin123', PASSWORD_BCRYPT)
// → '$2y$10$abc123...' (hash, beda setiap kali!)
password_verify('admin123', '$2y$10$abc123...')
// → true ✅
password_verify('salah', '$2y$10$abc123...')
// → false ❌
<?php
// ============================================
// FILE: auth/login.php
// Halaman login sistem POS
// ============================================
session_start(); // Wajib di awal sebelum pakai $_SESSION
// Jika sudah login, langsung ke dashboard
if (isset($_SESSION['user_id'])) {
header('Location: ../dashboard.php');
exit();
}
// Inisialisasi variabel
$error = '';
$username_input = ''; // Untuk mengisi ulang form jika error
// ============================================
// PROSES LOGIN (saat form di-submit)
// ============================================
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Ambil & bersihkan input
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$username_input = htmlspecialchars($username);
// Validasi: pastikan tidak kosong
if (empty($username) || empty($password)) {
$error = 'Username dan password harus diisi!';
} else {
// Koneksi database
require_once '../config/database.php';
// Cari user berdasarkan username
// Gunakan Prepared Statement untuk keamanan!
$stmt = $pdo->prepare(
"SELECT * FROM users WHERE username = ? LIMIT 1"
);
$stmt->execute([$username]);
$user = $stmt->fetch();
// Verifikasi: user ada DAN password cocok
if ($user && password_verify($password, $user['password'])) {
// Login berhasil! Simpan data ke session
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_nama'] = $user['nama'];
$_SESSION['user_role'] = $user['role'];
// Regenerate session ID untuk keamanan
// (mencegah Session Fixation Attack)
session_regenerate_id(true);
// Redirect ke dashboard
header('Location: ../dashboard.php');
exit();
} else {
// Login gagal
$error = 'Username atau password salah!';
// JANGAN beritahu mana yang salah (username atau password)
// karena itu petunjuk bagi hacker!
}
}
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login — Sistem POS</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
body {
background: linear-gradient(135deg, #1e3a8a 0%, #7c3aed 100%);
min-height: 100vh;
display: flex;
align-items: center;
}
.login-card {
border: none;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.login-logo {
width: 80px; height: 80px;
background: linear-gradient(135deg, #2563eb, #7c3aed);
border-radius: 20px;
display: flex; align-items: center; justify-content: center;
font-size: 2rem; margin: 0 auto 16px;
}
.form-control:focus {
border-color: #2563eb;
box-shadow: 0 0 0 0.25rem rgba(37, 99, 235, 0.25);
}
.btn-login {
background: linear-gradient(135deg, #2563eb, #7c3aed);
border: none; border-radius: 10px;
padding: 12px; font-weight: 600; font-size: 1rem;
transition: opacity 0.2s;
}
.btn-login:hover { opacity: 0.9; }
.input-group-text { border-right: none; }
.form-control { border-left: none; }
</style>
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-5 col-lg-4">
<div class="card login-card p-4">
<!-- Logo & Judul -->
<div class="text-center mb-4">
<div class="login-logo">🛒</div>
<h4 class="fw-bold">Sistem POS</h4>
<p class="text-muted small">Silakan login untuk melanjutkan</p>
</div>
<!-- Tampilkan error jika ada -->
<?php if ($error): ?>
<div class="alert alert-danger py-2 small">
<i class="fas fa-exclamation-circle me-1"></i>
<?= htmlspecialchars($error) ?>
</div>
<?php endif; ?>
<!-- Form Login -->
<form method="POST" action="">
<!-- Username -->
<div class="mb-3">
<label class="form-label fw-semibold">Username</label>
<div class="input-group">
<span class="input-group-text">
<i class="fas fa-user text-muted"></i>
</span>
<input
type="text"
name="username"
class="form-control"
placeholder="Masukkan username"
value="<?= $username_input ?>"
required autofocus
>
</div>
</div>
<!-- Password -->
<div class="mb-4">
<label class="form-label fw-semibold">Password</label>
<div class="input-group">
<span class="input-group-text">
<i class="fas fa-lock text-muted"></i>
</span>
<input
type="password"
name="password"
id="passwordInput"
class="form-control"
placeholder="Masukkan password"
required
>
<button
type="button"
class="btn btn-outline-secondary"
onclick="togglePassword()"
title="Lihat password"
>
<i class="fas fa-eye" id="eyeIcon"></i>
</button>
</div>
</div>
<!-- Tombol Login -->
<button type="submit" class="btn btn-primary btn-login w-100 text-white">
<i class="fas fa-sign-in-alt me-2"></i>Login
</button>
</form>
<!-- Info Demo -->
<div class="text-center mt-3 p-2 bg-light rounded">
<small class="text-muted">
Demo: username <code>admin</code> / password <code>password</code>
</small>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
function togglePassword() {
const input = document.getElementById('passwordInput');
const icon = document.getElementById('eyeIcon');
if (input.type === 'password') {
input.type = 'text';
icon.classList.replace('fa-eye', 'fa-eye-slash');
} else {
input.type = 'password';
icon.classList.replace('fa-eye-slash', 'fa-eye');
}
}
</script>
</body>
</html>
<?php
// ============================================
// FILE: auth/logout.php
// Proses logout: hapus semua session
// ============================================
session_start();
// 1. Hapus semua data session
$_SESSION = [];
// 2. Hapus cookie session
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(
session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
// 3. Hancurkan session
session_destroy();
// 4. Redirect ke halaman login
header('Location: login.php?logout=1');
exit();
?>
<?php
// ============================================
// FILE: includes/header.php
// Header yang diinclude di setiap halaman
// ============================================
// Pastikan session sudah dimulai
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Cek apakah user sudah login
// Jika belum, redirect ke login
if (!isset($_SESSION['user_id'])) {
// Simpan URL yang mau diakses (untuk redirect setelah login)
$_SESSION['redirect_after_login'] = $_SERVER['REQUEST_URI'];
header('Location: /pos_sederhana/auth/login.php');
exit();
}
// Ambil data user dari session
$currentUser = [
'id' => $_SESSION['user_id'],
'nama' => $_SESSION['user_nama'],
'role' => $_SESSION['user_role'],
];
// Tentukan halaman aktif untuk navbar
$currentPage = basename($_SERVER['PHP_SELF'], '.php');
$currentDir = basename(dirname($_SERVER['PHP_SELF']));
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $pageTitle ?? 'Sistem POS' ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
body { background-color: #f1f5f9; }
.navbar { background: linear-gradient(135deg, #1e3a8a, #2563eb) !important; }
.navbar-brand { font-weight: 800; font-size: 1.3rem; }
.nav-link { color: rgba(255,255,255,0.85) !important; border-radius: 8px; }
.nav-link:hover, .nav-link.active {
color: white !important;
background: rgba(255,255,255,0.15) !important;
}
.sidebar-wrapper { min-height: calc(100vh - 70px); }
.user-badge { background: rgba(255,255,255,0.15); border-radius: 20px; padding: 4px 12px; }
</style>
</head>
<body>
<!-- NAVBAR -->
<nav class="navbar navbar-expand-lg navbar-dark">
<div class="container-fluid px-4">
<!-- Brand -->
<a class="navbar-brand" href="/pos_sederhana/dashboard.php">
🛒 <span>Sistem POS</span>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="mainNav">
<!-- Menu kiri -->
<ul class="navbar-nav me-auto gap-1">
<li class="nav-item">
<a class="nav-link <?= ($currentPage==='dashboard') ? 'active' : '' ?>"
href="/pos_sederhana/dashboard.php">
<i class="fas fa-tachometer-alt me-1"></i>Dashboard
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= ($currentDir==='produk') ? 'active' : '' ?>"
href="/pos_sederhana/produk/index.php">
<i class="fas fa-box me-1"></i>Produk
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= ($currentDir==='transaksi') ? 'active' : '' ?>"
href="/pos_sederhana/transaksi/index.php">
<i class="fas fa-shopping-cart me-1"></i>Transaksi
</a>
</li>
<li class="nav-item">
<a class="nav-link <?= ($currentDir==='laporan') ? 'active' : '' ?>"
href="/pos_sederhana/laporan/index.php">
<i class="fas fa-chart-bar me-1"></i>Laporan
</a>
</li>
</ul>
<!-- User info kanan -->
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle d-flex align-items-center gap-2"
href="#" data-bs-toggle="dropdown">
<div class="user-badge">
<i class="fas fa-user-circle me-1"></i>
<?= htmlspecialchars($currentUser['nama']) ?>
<span class="badge bg-warning text-dark ms-1 small">
<?= ucfirst($currentUser['role']) ?>
</span>
</div>
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><h6 class="dropdown-header">
Halo, <?= htmlspecialchars($currentUser['nama']) ?>!
</h6></li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item text-danger" href="/pos_sederhana/auth/logout.php">
<i class="fas fa-sign-out-alt me-2"></i>Logout
</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<!-- Konten halaman mulai di sini -->
<div class="container-fluid py-4 px-4">
<?php
$pageTitle = 'Dashboard — Sistem POS';
require_once 'config/database.php';
require_once 'includes/header.php'; // Otomatis cek login
?>
<div class="row g-4 mb-4">
<div class="col-12">
<h4 class="fw-bold">
👋 Selamat Datang, <?= htmlspecialchars($_SESSION['user_nama']) ?>!
</h4>
<p class="text-muted"><?= date('l, d F Y') ?></p>
</div>
<?php
// Statistik: hitung data dari database
$totalProduk = $pdo->query("SELECT COUNT(*) FROM produk")->fetchColumn();
$totalHariIni = $pdo->query("SELECT COUNT(*) FROM transaksi WHERE DATE(tanggal) = CURDATE()")->fetchColumn();
$omzetHariIni = $pdo->query("SELECT COALESCE(SUM(total), 0) FROM transaksi WHERE DATE(tanggal) = CURDATE()")->fetchColumn();
$stokMenipis = $pdo->query("SELECT COUNT(*) FROM produk WHERE stok < 10")->fetchColumn();
?>
<!-- Kartu Statistik -->
<div class="col-md-3">
<div class="card border-0 shadow-sm h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted small">Total Produk</div>
<div class="h3 fw-bold mt-1"><?= $totalProduk ?></div>
</div>
<div class="p-3 rounded-3 bg-primary bg-opacity-10">
<i class="fas fa-box fa-2x text-primary"></i>
</div>
</div>
<a href="produk/index.php" class="btn btn-sm btn-outline-primary mt-2 w-100">Lihat Semua</a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted small">Transaksi Hari Ini</div>
<div class="h3 fw-bold mt-1"><?= $totalHariIni ?></div>
</div>
<div class="p-3 rounded-3 bg-success bg-opacity-10">
<i class="fas fa-shopping-cart fa-2x text-success"></i>
</div>
</div>
<a href="transaksi/index.php" class="btn btn-sm btn-outline-success mt-2 w-100">Buat Transaksi</a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted small">Omzet Hari Ini</div>
<div class="h4 fw-bold mt-1">
Rp <?= number_format($omzetHariIni, 0, ',', '.') ?>
</div>
</div>
<div class="p-3 rounded-3 bg-warning bg-opacity-10">
<i class="fas fa-money-bill fa-2x text-warning"></i>
</div>
</div>
<a href="laporan/index.php" class="btn btn-sm btn-outline-warning mt-2 w-100">Lihat Laporan</a>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="text-muted small">Stok Menipis (<10)</div>
<div class="h3 fw-bold mt-1 text-danger"><?= $stokMenipis ?></div>
</div>
<div class="p-3 rounded-3 bg-danger bg-opacity-10">
<i class="fas fa-exclamation-triangle fa-2x text-danger"></i>
</div>
</div>
<a href="produk/index.php?filter=stok_minim" class="btn btn-sm btn-outline-danger mt-2 w-100">Cek Stok</a>
</div>
</div>
</div>
</div>
<?php require_once 'includes/footer.php'; ?>