# SysMVC
**SysMVC** is a lightweight PHP MVC framework created by **Marco Costa** ([syspanel@gmx.com](mailto:syspanel@gmx.com)), licensed under the **MIT License**.
This software is free to use, modify, and distribute under the terms of the MIT License.
- **Website:** [https://sysmvc.duckdns.org](https://sysmvc.duckdns.org)
- **GitHub:** [https://github.com/syspanel/SysMVC](https://github.com/syspanel/SysMVC)
---
## Features
- **MVC Architecture** — clean separation of concerns with Models, Views, and Controllers
- **ORM (Eloquent)** — database access via `illuminate/database` (Laravel's Eloquent ORM)
- **Twin Template Engines** — BladeOne and Twig, configured side by side
- **Dependency Injection** — PHP-DI container with autowiring
- **Routing** — flexible HTTP routing via Pecee SimpleRouter
- **CSRF Protection** — built-in token generation and validation
- **Security Headers** — applied automatically via `BaseController`
- **Input/Output Sanitisation** — `Sanitizer` service with email and URL awareness
- **CLI Console** — Symfony Console commands for key generation and database migrations
- **Logging** — Monolog writes to `logs/app.log`
- **Mail** — Symfony Mailer integration
- **Authentication** — Delight Auth and PHP Auth libraries
---
## Requirements
| Requirement | Version |
|---|---|
| PHP | >= 7.4 |
| Composer | latest stable |
| Web Server | Apache or Nginx |
| Database | MySQL 5.7+ |
---
## Project Structure
```
app/
├── app/
│ ├── Controllers/ # HTTP controllers
│ ├── Models/ # Eloquent models
│ ├── Services/ # Shared services (BaseController, Sanitizer)
│ └── Console/Command/ # CLI console commands
├── bootstrap/
│ ├── app.php # Bootstrap: loads config, routes, container
│ ├── csrf.php # CSRF token helpers
│ └── helpers.php # Global helper functions
├── config/
│ ├── container.php # DI container definitions (Blade, Twig, Monolog)
│ ├── database.php # Eloquent ORM connection setup
│ ├── envread.php # .env loader (defines constants)
│ ├── paths.php # VIEWS_PATH and CACHE_PATH constants
│ └── templateengine.php # CSRF template helpers
├── database/
│ └── crudexample.sql # Sample SQL schema
├── routes/
│ ├── web.php # Web routes
│ ├── api.php # API routes (extend as needed)
│ └── auth.php # Auth routes (extend as needed)
├── resources/views/ # Blade and Twig template files
├── public/
│ └── index.php # Application entry point
├── storage/ # Uploads and generated files
├── cache/ # Compiled template cache
├── logs/ # Application log files
├── tests/
│ ├── Feature/ # Feature tests
│ └── Unit/ # Unit tests
├── bin/
│ └── console # CLI entry point
├── composer.json
└── .env # Environment configuration (gitignored)
```
---
## Installation
### 1. Clone or unzip the project
```bash
unzip sysmvc.zip -d sysmvc
cd sysmvc
```
### 2. Install PHP dependencies
```bash
composer install
```
### 3. Configure the environment
```bash
cp .env.example .env
```
Edit `.env` with your database and application settings:
```ini
# Application
APP_NAME=SysMVC
APP_ENV=production
APP_DEBUG=false
APP_URL=http://localhost:16270
# Database
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database_name
DB_USERNAME=your_username
DB_PASSWORD=your_password
```
### 4. Set directory permissions
```bash
chmod -R 775 storage
chmod -R 775 cache
chmod -R 775 logs
chmod -R 775 bootstrap/cache
```
### 5. Generate the application key
```bash
php bin/console generate:app-key
```
### 6. Set up the database
Create the database manually or run the sample migration command:
```bash
php bin/console migrate:crudexample
```
### 7. Configure the web server
**Apache** — add a virtual host pointing to the `public/` directory:
```apache
ServerName sysmvc.local
DocumentRoot /path/to/sysmvc/public
AllowOverride All
Require all granted
```
**Nginx** — add a server block pointing to the `public/` directory:
```nginx
server {
listen 80;
server_name sysmvc.local;
root /path/to/sysmvc/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
}
```
---
## CLI Commands
All CLI commands are available through the `bin/console` entry point:
```bash
php bin/console [command]
```
| Command | Description |
|---|---|
| `generate:app-key` | Generates a new `APP_KEY` and writes it to `.env` |
| `generate:api-keys` | Generates `API_PUBLIC_KEY` and `API_SECRET_KEY` in `.env` |
| `migrate:crudexample` | Creates the `crudexample` table with 30 sample records |
| `say:hello` | Example / demo command |
---
## Routing
Routes are defined in `routes/web.php` using Pecee SimpleRouter syntax.
### Example routes
```php
Router::get('/', [HomeController::class, 'index'])->name('home');
Router::get('/about', function () { ... })->name('about');
Router::post('/crudexample', [CrudExampleController::class, 'store'])->name('crudexample.store');
```
### Route groups
```php
Router::group(['prefix' => '/crudexample'], function () {
Router::get('/', 'CrudExampleController@index')->name('crudexample.index');
Router::get('/create', 'CrudExampleController@create')->name('crudexample.create');
Router::get('/edit/{id}', 'CrudExampleController@edit')->name('crudexample.edit');
Router::post('/store', 'CrudExampleController@store')->name('crudexample.store');
Router::post('/update/{id}', 'CrudExampleController@update')->name('crudexample.update');
Router::post('/delete/{id}', 'CrudExampleController@delete')->name('crudexample.delete');
Router::get('/show/{id}', 'CrudExampleController@show')->name('crudexample.show');
});
```
404 errors are handled by a global error handler that renders `resources/views/errors/404.html`.
---
## Security
SysMVC includes multiple security layers, all applied automatically.
### Security Headers (`BaseController`)
Applied to every controller that extends `BaseController`:
| Header | Value |
|---|---|
| `Content-Security-Policy` | `default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:` |
| `X-Frame-Options` | `DENY` |
| `X-Content-Type-Options` | `nosniff` |
| `Referrer-Policy` | `no-referrer` |
| `Strict-Transport-Security` | `max-age=31536000; includeSubDomains; preload` |
### CSRF Protection
Tokens are generated per session via `generateCsrfToken()` in `bootstrap/csrf.php`. Include the hidden field in forms with:
```php
= csrf() ?>
```
### Input Sanitisation
All form inputs are sanitised through `Sanitizer::sanitizeInput()` before storage. Output escaping is applied via `Sanitizer::sanitizeOutput()` before rendering.
### Password Storage
Passwords are hashed with `password_hash($password, PASSWORD_BCRYPT)` before being persisted.
---
## Environment Variables
Key environment variables loaded from `.env`:
| Variable | Default | Description |
|---|---|---|
| `APP_NAME` | `SysMVC` | Application name |
| `APP_KEY` | — | Random encryption key |
| `APP_ENV` | `production` | Environment: `production` / `local` / `testing` |
| `APP_DEBUG` | `false` | Display error details |
| `APP_URL` | — | Base URL of the application |
| `DB_CONNECTION` | `mysql` | Database driver |
| `DB_HOST` | `127.0.0.1` | Database host |
| `DB_PORT` | `3306` | Database port |
| `DB_DATABASE` | — | Database name |
| `DB_USERNAME` | — | Database user |
| `DB_PASSWORD` | — | Database password |
| `SESSION_DRIVER` | `file` | Session driver |
| `SESSION_LIFETIME` | `120` | Session duration in minutes |
PHP runtime settings are also configurable via `PHP_MEMORY_LIMIT`, `PHP_MAX_EXECUTION_TIME`, `PHP_DISPLAY_ERRORS`, and related variables in `.env`.
---
## Dependencies
| Package | Version | License |
|---|---|---|
| `illuminate/database` | ^8.0 | MIT |
| `phpauth/phpauth` | ^1.0 | MIT |
| `monolog/monolog` | ^2.0 | MIT |
| `eftec/bladeone` | ^4.0 | MIT |
| `eftec/bladeonehtml` | ^2.5 | MIT |
| `twig/twig` | ^3.20 | BSD-3-Clause |
| `symfony/console` | ^5.0 | MIT |
| `symfony/mailer` | ^7.2 | MIT |
| `symfony/cache` | ^5.0 | MIT |
| `symfony/dotenv` | ^6.4 | MIT |
| `symfony/event-dispatcher` | ^5.0 | MIT |
| `symfony/filesystem` | ^5.0 | MIT |
| `symfony/translation` | ^5.0 | MIT |
| `symfony/mime` | ^6.4 | MIT |
| `robmorgan/phinx` | ^0.12.0 | MIT |
| `defuse/php-encryption` | ^2.2 | MIT |
| `paragonie/random_compat` | ^9.99 | MIT |
| `rakit/validation` | ^1.4 | MIT |
| `nesbot/carbon` | ^2.0 | MIT |
| `league/flysystem` | ^1.1 | MIT |
| `intervention/image` | ^2.5 | MIT |
| `predis/predis` | ^1.1 | MIT |
| `php-di/php-di` | ^7.0 | MIT |
| `pecee/simple-router` | ^5.4 | MIT |
| `nyholm/psr7` | ^1.8 | MIT |
| `fakerphp/faker` | ^1.24 | MIT |
| `delight-im/auth` | ^8.3 | MIT |
| `delight-im/db` | ^8.3 | MIT |
| `delight-im/cookie` | ^8.3 | MIT |
| `delight-im/http` | ^8.3 | MIT |
| `google/recaptcha` | ^1.2 | BSD-3-Clause |
| `guzzlehttp/guzzle` | ^7.0 | MIT |
| `guzzlehttp/promises` | ^1.5 | MIT |
| `guzzlehttp/psr7` | ^2.0 | MIT |
---
## License
This project is licensed under the **MIT License**. You may use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, provided the original license and copyright notice are included.
See [LICENSE](LICENSE) for the full license text.
© 2025 Marco Costa — All rights reserved under the MIT License.