feras_altaleb/mvc_php

Enterprise-Ready PHP MVC Framework Template

Maintainers

Package info

github.com/AltalebFeras/template_empty_mvc_for_any_new_project_php_native

Type:project

pkg:composer/feras_altaleb/mvc_php

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-08-22 15:49 UTC

This package is auto-updated.

Last update: 2026-08-22 15:49:46 UTC


README

A hyper-secure, high-performance native PHP MVC application template designed for enterprise-grade production deployments. Zero framework dependencies — only essential, audited libraries.

📚 Detailed Technical Documentation: Full feature guides, API references, and architecture details are available in the docs/ folder.

Table of Contents

Architecture

Request → Nginx/Apache → public/index.php → init.php (bootstrap)
  ├── Config::boot()          Load .env
  ├── SecurityHeaders::send() Set CSP, HSTS, etc.
  ├── RequestLogger::log()    Log request start
  └── router.php              Dispatch to controller
       ├── CSRF validation
       ├── Auth guard
       ├── RBAC role check
       ├── ABAC permission check
       └── Controller::method()
            ├── Validator::validate()
            ├── Repository (PDO Singleton)
            └── render() / ApiResponse::success()

Design Principles

  • Defense-in-Depth: Multiple overlapping security layers
  • PSR-4 Autoloading: App\ namespace mapped to src/
  • Convention over Configuration: Repositories auto-map to tables and entities
  • Fail-Fast: Required config validated on boot, strict PDO error mode
  • Zero Trust: Every request authenticated, authorized, and rate-limited

Features

Security

  • ✅ AES-256-GCM authenticated encryption (AEAD)
  • ✅ Argon2id password hashing (64MB memory cost)
  • ✅ Per-form CSRF tokens with expiry
  • ✅ Hardened HTTP headers (CSP, HSTS, COOP, CORP)
  • ✅ Session fingerprinting (IP + User-Agent binding)
  • ✅ Automatic session regeneration & idle timeout
  • ✅ Cloudflare Turnstile bot protection
  • ✅ Sliding-window rate limiting
  • ✅ Fail2Ban-compatible threat logging
  • ✅ Secure file uploads (MIME verification, UUID rename, EXIF stripping)
  • ✅ SVG sanitization (XSS prevention)
  • ✅ IDOR prevention (ownership verification)

Performance

  • ✅ Singleton PDO connection
  • ✅ Generator-based streaming for large result sets
  • ✅ Multi-tier caching (Memory → Redis → File)
  • ✅ OPcache + JIT configuration
  • ✅ Response compression (gzip)
  • ✅ ETag + 304 Not Modified support
  • ✅ Non-blocking sessions (session_write_close())

Architecture

  • ✅ RBAC + ABAC authorization middleware
  • ✅ Attribute-based routing (#[Route('/path')])
  • ✅ Normalized API responses (status, data, errors, meta)
  • ✅ Input validation engine (18+ rules)
  • ✅ Background job queue with retry/backoff
  • ✅ Circuit breaker for external APIs
  • ✅ Database migration system (up/down)
  • ✅ Structured JSON logging (PSR-3 / Monolog)
  • ✅ Health check endpoints (/health, /ready)
  • ✅ CORS middleware
  • ✅ Docker-ready (PHP-FPM + Nginx + MySQL + Redis)

Prerequisites

Requirement Version
PHP ≥ 8.2
Composer ≥ 2.0
MySQL / PostgreSQL 8.0+ / 16+
Redis 7+ (optional)

Required PHP Extensions

pdo_mysql    openssl    mbstring    curl
gd           json       fileinfo   session

Optional: redis, imagick, apcu

Installation

1. Clone & Install Dependencies

git clone <repository-url> myproject
cd myproject
composer install

2. Configure Environment

cp .env.example .env

Edit .env with your settings. Generate an encryption key:

php -r "echo bin2hex(random_bytes(32));"

Paste the output as APP_KEY in .env.

3. Create Database & Run Migrations

# Create your database manually, then:
composer migrate
# or
php bin/migrate.php up

4. Set Permissions

chmod -R 755 storage/ logs/
chown -R www-data:www-data storage/ logs/

5. Start Development Server

# Using PHP built-in server:
php -S localhost:8080 -t public/

# Or using Docker:
docker-compose up -d
# App available at http://localhost:8080

Configuration

All configuration is managed via .env. See .env.example for all available keys.

Key Description Default
APP_ENV Environment (development/production/testing) development
APP_DEBUG Show debug info true
APP_KEY 64-hex-char encryption key (required)
APP_URL Base application URL http://localhost
DB_HOST Database host 127.0.0.1
DB_NAME Database name (required)
SESSION_IDLE_TIMEOUT Auto-logout idle time (seconds) 1800
TURNSTILE_SITE_KEY Cloudflare Turnstile public key
RATE_LIMIT_LOGIN Max login attempts per window 5

Access configuration in code:

use App\Services\Config;

$debug = Config::isDebug();
$url   = Config::baseUrl();
$host  = Config::get('DB_HOST', '127.0.0.1');
$port  = Config::getInt('DB_PORT', 3306);

Database Migrations

Migrations live in src/Migrations/ as PHP files returning ['up' => '...SQL...', 'down' => '...SQL...'].

# Run all pending migrations
php bin/migrate.php up

# Roll back the last migration
php bin/migrate.php down

# Show migration status
php bin/migrate.php status

Creating a Migration

Create a file in src/Migrations/ with timestamp prefix:

<?php
// src/Migrations/2024_004_create_posts_table.php
return [
    'up' => "
        CREATE TABLE `posts` (
            `post_id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            `user_id` INT UNSIGNED NOT NULL,
            `title`   VARCHAR(255) NOT NULL,
            `body`    TEXT NOT NULL,
            `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
            FOREIGN KEY (`user_id`) REFERENCES `users`(`user_id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    ",
    'down' => "DROP TABLE IF EXISTS `posts`;",
];

Request Lifecycle

  1. public/index.php → requires src/init.php
  2. Config.env loaded via Dotenv
  3. Error handler → exceptions logged, clean 500 page in production
  4. Session → secure init, idle timeout, periodic regeneration
  5. Security headers → CSP, HSTS, X-Frame-Options sent
  6. Request logging → method, path, timing captured
  7. Router#[Route] attributes scanned on controllers
  8. CSRF → validated on POST/PUT/PATCH/DELETE
  9. Auth guard → session checked if authRequired: true
  10. RBAC/ABAC → roles and permissions verified
  11. Controller → business logic executed
  12. View/API → HTML rendered or JSON returned

Security

See SECURITY.md for the full security operations runbook.

Quick Reference

// Encrypt/decrypt sensitive data
$enc = new Encryption();
$cipher = $enc->encrypt('sensitive-data');
$plain  = $enc->decrypt($cipher);

// Hash passwords
$hash = PasswordHasher::hash($password);
$ok   = PasswordHasher::verify($password, $hash);

// CSRF protection (in forms)
<?= Csrf::inputField() ?>

// CSRF for AJAX
headers: { 'X-CSRF-Token': '<?= Csrf::getToken() ?>' }

// Escape output
<?= Validator::escape($userInput) ?>

Authentication

The UserController provides a complete authentication flow:

// Routes:
#[Route('/login', methods: ['GET'])]     // Display login form
#[Route('/login', methods: ['POST'])]    // Process login
#[Route('/logout', methods: ['POST'])]   // Logout
#[Route('/dashboard', authRequired: true)] // Protected page

Login process:

  1. Rate limit check (5 attempts/minute)
  2. Cloudflare Turnstile verification
  3. Input validation
  4. Email lookup + Argon2id password verification
  5. Transparent password rehash if needed
  6. Session regeneration + CSRF refresh
  7. Session fingerprinting (IP + UA)

Authorization (RBAC/ABAC)

Route-Level Authorization

// Require authentication
#[Route('/profile', authRequired: true)]

// Require specific role
#[Route('/admin', roles: ['admin'])]

// Require specific permission
#[Route('/posts/create', permissions: ['posts.write'])]

// Combine
#[Route('/users/delete', methods: ['DELETE'], authRequired: true, roles: ['admin'])]

Code-Level Authorization

use App\Services\Authorization;

// Check role
if (Authorization::hasRole('editor')) { ... }

// Check permission
if (Authorization::can('posts.delete')) { ... }

// Check ownership (IDOR prevention)
if (Authorization::canAccess($post->getUserId())) { ... }

// Guard methods (throw 403)
Authorization::requireRole('admin');
Authorization::requirePermission('users.write');

API Development

Response Format

use App\Services\ApiResponse;

// Success (200)
ApiResponse::success(['user' => $user]);

// Created (201)
ApiResponse::created(['id' => $newId]);

// Error (422)
ApiResponse::error(['Invalid email address.'], 422);

// Paginated
ApiResponse::paginated($items, $total, $page, $perPage);

// No Content (204)
ApiResponse::noContent();

All responses follow this structure:

{
    "status": "success|error",
    "data": {},
    "errors": null,
    "meta": { "pagination": { ... } }
}

Input Validation

$errors = Validator::validate($_POST, [
    'email'    => ['required', 'email', 'max:255'],
    'password' => ['required', 'min:8', 'confirmed'],
    'role'     => ['in:user,editor,admin'],
    'website'  => ['url'],
    'slug'     => ['slug'],
], [
    'email.required' => 'Email is mandatory.',
]);

if (!empty($errors)) {
    ApiResponse::error($errors, 422);
}

File Uploads

use App\Services\FileUpload;
use App\Services\ImageProcessor;

$upload = new FileUpload();
$result = $upload->store($_FILES['avatar']);
// $result['name'] = 'a1b2c3d4...f0.jpg'
// $result['path'] = '/storage/uploads/a1b2c3d4...f0.jpg'

// Strip EXIF metadata
ImageProcessor::sanitize($result['path']);

// Generate thumbnail
ImageProcessor::thumbnail($result['path'], 300, 300);

Caching

use App\Services\Cache;

// Set/get
Cache::set('user:42', $userData, 3600);
$user = Cache::get('user:42');

// Remember pattern
$result = Cache::remember('expensive:query', 600, function() {
    return $db->heavyQuery();
});

// Delete
Cache::delete('user:42');
Cache::flush();

Background Jobs

use App\Services\JobQueue;

// Enqueue
JobQueue::dispatch('send_email', [
    'to'      => 'user@example.com',
    'subject' => 'Welcome!',
    'body'    => 'Your account is active.',
]);

// Delayed job (run in 5 minutes)
JobQueue::dispatch('send_reminder', $payload, delay: 300);

Run the worker:

php bin/worker.php              # Run indefinitely
php bin/worker.php --max=100    # Process 100 jobs then exit

Cloudflare Turnstile

1. Get Credentials

Register at Cloudflare Dashboard and obtain your Site Key + Secret Key.

2. Configure

TURNSTILE_SITE_KEY=0x4AAAAAAA...
TURNSTILE_SECRET_KEY=0x4AAAAAAA...

3. Add Widget to Forms

<form method="POST" action="/login">
    <?= Csrf::inputField() ?>
    <!-- form fields -->
    <?php include __DIR__ . '/../includes/turnstile.php'; ?>
    <button type="submit">Login</button>
</form>

4. Verify Server-Side

$result = Turnstile::verify($_POST['cf-turnstile-response']);
if ($result->failed()) {
    // Reject the request
}

Docker Deployment

# Build and start all services
docker-compose up -d

# Services:
#   app     — PHP 8.2 FPM (port 9000)
#   web     — Nginx (port 8080)
#   db      — MySQL 8.0 (port 3306)
#   redis   — Redis 7 (port 6379)
#   mailpit — Mail catcher (SMTP 1025, UI 8025)

# View logs
docker-compose logs -f app

# Run migrations inside container
docker-compose exec app php bin/migrate.php up

# Run tests
docker-compose exec app composer test

Web Server Configuration

Nginx

See docker/nginx/default.conf for the production-ready configuration.

Key rules:

  • Document root: public/
  • Deny access to: .env, vendor/, src/, bin/, logs/, storage/
  • Block PHP execution in storage/
  • Gzip compression enabled
  • Static assets cached for 1 year

Apache

The public/.htaccess includes:

  • URL rewriting (all routes → index.php)
  • Security headers
  • Gzip compression
  • Browser caching rules
  • HTTPS redirect (uncomment in production)

Critical: Ensure AllowOverride All is set in your Apache vhost.

Testing

# Run all tests
composer test

# Run specific suite
vendor/bin/phpunit --testsuite Unit
vendor/bin/phpunit --testsuite Integration

# Static analysis (level 6)
composer analyse

# Security audit
composer audit

Maintenance

Regular Tasks

Task Command Frequency
Dependency audit composer audit Every build
Update dependencies composer update Monthly
Rotate APP_KEY Manual (see SECURITY.md) Bi-annually
Review security logs tail logs/security-threats.log Weekly
Clear expired cache Cache::flush() As needed
Prune old job records SQL cleanup Monthly

Health Checks

# Application health
curl http://localhost:8080/health

# Readiness probe
curl http://localhost:8080/ready

Component Reference

For complete method signatures, internal logic, and advanced usage, see docs/23-component-reference.md.

Key Components Overview

Category File Description & Usage Summary
Controllers FileController.php Serves uploaded files securely from /storage/uploads outside web root with MIME checking (finfo), path traversal protection (realpath), and inline/attachment dispositions.
HealthController.php Operational probes (GET /health for database/Redis check, GET /ready for Kubernetes readiness probes).
Middleware Cors.php Fine-grained Cross-Origin Resource Sharing handling allowed origins, headers, and preflight OPTIONS requests.
RateLimiter.php Sliding window rate limiting using Redis sorted sets (with JSON file fallback) and automated threat logging.
RequestLogger.php Measures execution duration (ms) and memory usage (MB) for HTTP requests; logs on shutdown.
SecurityHeaders.php Sends defense-in-depth headers (CSP, HSTS, X-Frame-Options, nosniff, Permissions-Policy, COOP/CORP).
ThreatLogger.php Fail2Ban and WAF compatible security logger (logs/security-threats.log) with automatic PII masking.
Migrations 2024_001_create_users_table.php Defines users database schema with Argon2id password comments and index structures.
2024_002_create_roles_permissions_tables.php Creates RBAC schema (roles, permissions, role_permissions) and seeds default user roles.
2024_003_create_jobs_table.php Schema for the background job queue table with status tracking and JSON payloads.
Services ApiResponse.php Standardized REST JSON responses (success, error, paginated, created, noContent).
Authorization.php Role-Based (RBAC) and Attribute-Based (ABAC) access control supporting wildcards and ownership verification (owns).
Cache.php Multi-tier cache (L1 Memory array → L2 Redis → L3 File fallback) with remember() pattern.
CircuitBreaker.php Resiliency pattern for external API calls (CLOSED, OPEN, HALF_OPEN) preventing cascading failures.
Config.php Singleton .env configuration loader enforcing required environment keys and typed getters.
ConfigRouter.php Request utilities (_method HTTP spoofing, session IP/UA origin check, getClientIp, redirect).
Csrf.php Cryptographic CSRF token generation, per-form token scoping, and constant-time validation (hash_equals).
Database.php Singleton PDO manager configured with strict error mode (ERRMODE_EXCEPTION) and health checking (isHealthy).
Encryption.php Symmetric AEAD encryption using AES-256-GCM with random 12-byte IVs and authentication tags.
FileUpload.php Secure upload handler with magic-byte MIME verification, extension whitelisting, UUID renaming, and memory bomb checks.
Hydration.php Trait for auto-hydrating entity properties (snake_case DB columns → setCamelCase setters) and serialization.
ImageProcessor.php Privacy EXIF metadata stripper, aspect-ratio preserving thumbnail generator, and SVG XSS sanitizer.
JobQueue.php SQL task queue supporting FOR UPDATE SKIP LOCKED, atomic locks, and exponential backoff retries.
Logger.php Monolog structured JSON logging wrapper with app, security, and db channels.
Mail.php PHPMailer SMTP email dispatch service supporting HTML templates and attachments.
Migrator.php Migration runner handling up(), down(), and status() tracked via database table _migrations.
PasswordHasher.php Hashing service using Argon2id (64MB memory cost, 4 time cost) with automatic rehash verification.
ResponseCompressor.php Output buffer wrapper generating ETag headers for 304 responses and transparent gzip compression.
Route.php PHP 8 attribute (#[Route('/path', methods: [...])]) for declarative endpoint configuration.
router.php Reflection route scanner and middleware pipeline dispatcher (CSRF → Auth → RBAC → ABAC → Controller).
Turnstile.php Cloudflare Turnstile CAPTCHA server-side token verification client.
Validator.php Input validation engine with 18+ rules (required, email, confirmed, slug, etc.) and HTML string escaping.
CLI Scripts bin/migrate.php CLI entry point for running database migrations (`php bin/migrate.php up
bin/worker.php CLI entry point for background job queue worker execution (php bin/worker.php [--max=N]).

Directory Structure

project-root/
├── bin/                        # CLI scripts
│   ├── migrate.php             # Database migrations
│   └── worker.php              # Job queue worker
├── docker/                     # Docker configuration
│   └── nginx/default.conf      # Nginx vhost config
├── logs/                       # Application logs (gitignored)
├── public/                     # Web root (document root)
│   ├── .htaccess               # Apache rewrite rules
│   ├── index.php               # Entry point
│   ├── assets/css/             # Stylesheets
│   ├── assets/js/              # JavaScript
│   ├── robots.txt
│   └── sitemap.xml
├── src/                        # Application source (App\ namespace)
│   ├── Abstracts/              # Abstract base classes
│   │   ├── AbstractController  # View rendering, redirects
│   │   └── AbstractRepository  # CRUD, transactions, streaming
│   ├── Controllers/            # Request handlers
│   │   ├── FileController      # Secure file serving
│   │   ├── HealthController    # Health/readiness endpoints
│   │   ├── HomeController      # Public pages, error pages
│   │   └── UserController      # Authentication flows
│   ├── Entities/               # Data models
│   │   └── User
│   ├── Middleware/              # Request/response middleware
│   │   ├── Cors                # Cross-origin resource sharing
│   │   ├── RateLimiter         # Sliding-window rate limiting
│   │   ├── RequestLogger       # Request timing/logging
│   │   ├── SecurityHeaders     # CSP, HSTS, etc.
│   │   └── ThreatLogger        # Fail2Ban-compatible logging
│   ├── Migrations/             # Database migration files
│   ├── Repositories/           # Data access layer
│   │   └── UserRepository
│   ├── Services/               # Core services
│   │   ├── ApiResponse         # Normalized JSON responses
│   │   ├── Authorization       # RBAC/ABAC engine
│   │   ├── Cache               # Multi-tier caching
│   │   ├── CircuitBreaker      # External API resilience
│   │   ├── Config              # Environment configuration
│   │   ├── ConfigRouter        # Request helpers
│   │   ├── Csrf                # CSRF token management
│   │   ├── Database            # Singleton PDO connection
│   │   ├── Encryption          # AES-256-GCM encryption
│   │   ├── FileUpload          # Secure file handling
│   │   ├── Hydration           # Entity auto-hydration trait
│   │   ├── ImageProcessor      # Image sanitization/thumbnails
│   │   ├── JobQueue            # Background job processing
│   │   ├── Logger              # Structured logging (Monolog)
│   │   ├── Mail                # Email service (PHPMailer)
│   │   ├── Migrator            # Migration engine
│   │   ├── PasswordHasher      # Argon2id hashing
│   │   ├── ResponseCompressor  # Gzip + ETag
│   │   ├── Route               # Route attribute definition
│   │   ├── Turnstile           # Cloudflare bot protection
│   │   └── Validator           # Input validation engine
│   ├── Views/                  # PHP templates
│   └── init.php                # Application bootstrap
├── storage/                    # Uploads & cache (gitignored)
│   ├── cache/
│   └── uploads/
├── tests/                      # PHPUnit test suite
│   ├── Unit/
│   └── bootstrap.php
├── .env.example                # Environment template
├── .gitignore
├── composer.json
├── docker-compose.yml
├── Dockerfile
├── opcache.ini
├── phpstan.neon
├── phpunit.xml
├── readme.md                   # This file
└── SECURITY.md                 # Security operations runbook

License

MIT License. See LICENSE for details.