Modular framework-free PHP login system with role-based routing, user registration with admin approval, and a built-in user management panel — runs on plain PHP/PDO/MySQL, drop-in ready for XAMPP.
Find a file
2026-09-10 13:37:52 +02:00
app Initial commit 2026-09-10 13:37:52 +02:00
config Initial commit 2026-09-10 13:37:52 +02:00
includes Initial commit 2026-09-10 13:37:52 +02:00
pages Initial commit 2026-09-10 13:37:52 +02:00
sql Initial commit 2026-09-10 13:37:52 +02:00
tools Initial commit 2026-09-10 13:37:52 +02:00
.htaccess Initial commit 2026-09-10 13:37:52 +02:00
index.php Initial commit 2026-09-10 13:37:52 +02:00
README.md Initial commit 2026-09-10 13:37:52 +02:00

PHP Login, Registration & Role System

A modular PHP foundation with central routing, role-based access control, login/registration against a MySQL user table, and a user-management area for administrators.

Setup in XAMPP

  1. Copy this entire folder into C:\xampp\htdocs\<any-folder-name>. The folder name is completely free to choose — routing adapts automatically.
  2. Start Apache and MySQL in XAMPP.
  3. In phpMyAdmin, create a database, e.g. meine_datenbank.
  4. Import sql/database.sql into that database — it contains the full table setup (this is the single, complete SQL file for the project).
  5. Open config/database.php and adjust the credentials (host, database name, user, password) to match your environment.
  6. Make sure Apache has mod_rewrite and mod_authz_core enabled (default in XAMPP) and that AllowOverride All is set for htdocs, so the .htaccess files take effect.
  7. Create the first administrator (required — otherwise nobody can access /admin/users):
    • Open in your browser: http://localhost/<folder-name>/tools/generate_hash.php?pw=test1234
    • Copy the generated INSERT statement into phpMyAdmin and run it (see also the comments in sql/database.sql).
    • Afterwards, delete tools/generate_hash.php or lock down the tools/ folder.
  8. Open in your browser: http://localhost/<folder-name>/

Flow for new users

  1. A user registers at /register → gets the pending role.
  2. They can log in, but /dashboard only shows a message that the account is awaiting approval.
  3. An administrator opens /admin/users, clicks "Edit" next to that user, and assigns a proper role (role1, role2, role3, or admin).
  4. From then on, the user has access to whatever pages their role is allowed to see.

Project structure

config/database.php     Central DB connection ($pdo)
config/routes.php       Central routing table (URL -> file + roles)
config/roles.php        Central list of all roles (used for dropdowns)
app/bootstrap.php       Loads DB, session, helpers, auth; blocks direct file access
app/helpers.php         url()/redirectTo() (subfolder-safe), flash messages
app/auth.php            Login, registration, profile, role checks
app/router.php          Reads routes.php, checks access, loads the page
includes/header.php     Shared page header incl. water.css, navigation, flash messages
includes/footer.php     Shared page footer
pages/*.php             The actual page content
sql/database.sql        Single SQL file: table creation + first-admin instructions
tools/generate_hash.php Helper script to generate password hashes

Adding a new page

  1. Create a new file under pages/, following the pattern of pages/role1_area.php. Always start with require_once __DIR__ . '/../app/bootstrap.php';, and always use the url('/path') helper for links instead of hardcoded /path strings — this keeps the app working in any subfolder.
  2. Add an entry to config/routes.php:
'/my-url' => [
    'file'  => 'pages/my_page.php',
    'roles' => ['role1', 'role2'], // or ['ALL'] for public, ['AUTH'] for any logged-in user
],

The router automatically takes care of the login and role checks.

Roles

There are five fixed roles (see config/roles.php):

  • pending — automatically assigned after registration, no extended access
  • role1, role2, role3 — the three application-level roles
  • admin — access to user management (/admin/users)

Use roles => ['ALL'] for public pages (no login required), and roles => ['AUTH'] for pages any logged-in user may see, regardless of their specific role.

Notes on the routing/subfolder fix

Page files are required from inside the route() function in app/router.php, which runs them in that function's local scope. Because of this, any page that needs the database connection directly (rather than through a helper function in app/auth.php) must declare global $pdo; before using it — this is already done in all pages/admin_*.php files.

The BASE_PATH constant (see app/helpers.php) is derived from dirname($_SERVER['SCRIPT_NAME']), so the router and every generated link work correctly regardless of which subfolder of htdocs the project is installed in.