A lightweight, modern PHP framework with built-in authentication, access control, and administrative utilities.
/floe) - Central hub for all administrative tools/floe/db-schema) - Export complete database schema (tables + views)/floe/users) - Manage users, reset passwords, toggle active status, 2FA settings/floe/logged-users) - View currently logged-in users with logout capability/floe/access-control) - Assign page permissions to users/floe/sessions) - Monitor logged-in users and session data/floe/activity-log) - User action tracking and audit trail (login/logout/page views)/floe/routes) - View all registered routes with file validation/floe/db-test) - Test database connectivity/floe/email-test) - Send test emails to verify SMTP configuration/floe/samples/table) - DataTables demo with SearchPanes and Slovak localization/floe/samples/pivot) - Interactive data analysis with PivotTable.js/floe/samples/crud) - AJAX CRUD operations with real-time updates/floe/samples/form) - Form handling with Quill editor, emoji picker, FilePond uploads/floe/samples/alerts) - SweetAlert2 beautiful notifications and confirmation dialogs/floe/samples/email-builder) - Rich HTML email editor with PHP variables, buttons, database storage/floe/samples/excel-import) - Upload and import Excel files (XLS, XLSX, ODS) to database/floe/samples/s3-upload) - Upload files to DigitalOcean Spaces (S3-compatible storage)/floe/samples/pdf) - Generate and merge PDFs with TCPDF library (HTML, tables, formatting)/floe/samples/word) - Generate DOCX files from templates with PHPWord/floe/samples/map) - OpenStreetMap integration with markers and geolocation/floe/deploy) - Automatic deployment via GitHub webhooks1. Clone or download the framework
git clone https://github.com/kkassovic/Floe.git my-project
cd my-project
2. Install dependencies
``bash
composer require phpmailer/phpmailer
composer require twilio/sdk
composer require vlucas/phpdotenv
composer require phpoffice/phpword
composer require phpoffice/phpspreadsheet
composer require aws/aws-sdk-php
composer require tecnickcom/tcpdf
composer require setasign/fpdi
3. Configure environment
`bash
cp config/.env.example config/.env
Edit config/.env with your settings:
`env
DB_HOST=localhost
DB_NAME=your_database
DB_USER=your_username
DB_PASS=your_password
SESSION_LIFETIME=2592000 # 30 days
# Optional: S3/DigitalOcean Spaces
S3_KEY=your_access_key
S3_SECRET=your_secret_key
S3_REGION=nyc3
S3_ENDPOINT=https://nyc3.digitaloceanspaces.com
S3_BUCKET=floe-storage
# Optional: GitHub Deployment
DEPLOY_SECRET=your_random_secret
DEPLOY_BRANCH=main
4. Create database schema
`sql
-- Run floe/complete_schema.sql
mysql -u your_username -p your_database < floe/complete_schema.sql
5. Configure Apache
Ensure .htaccess is enabled and contains:
`apache
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ front_cont.php [QSA,L]
6. Set file permissions
`bash
chmod 755 logs/
chmod 644 config/.env
7. Access your application
- Homepage: http://localhost/
- Login: http://localhost/login
- Admin utilities: http://localhost/floe/
Project Structure
/
├── front_cont.php # Front controller (entry point)
├── .htaccess # URL rewriting rules
├── routes.php # Route definitions
├── index_cont.php # Homepage controller
├── index_view.php # Homepage view
├── composer.json # Dependencies
├── config/
│ ├── .env # Environment configuration (DO NOT COMMIT)
│ └── .env.example # Environment template
├── floe/ # Framework core
│ ├── Auth.php # Authentication class
│ ├── Database.php # Database abstraction
│ ├── Renderer.php # Template renderer
│ ├── Router.php # URL routing
│ ├── AccessGuard.php # Page permissions
│ ├── LoginGuard.php # Public/private pages
│ ├── Mailer.php # Email wrapper
│ ├── Geolocation.php # IP geolocation
│ ├── complete_schema.sql # Complete database schema
│ └── *.md # Documentation files
├── app/
│ ├── floe/ # Admin utility controllers/views
│ │ ├── *_controller.php
│ │ ├── *_view.php
│ │ ├── 403.php # Access denied page
│ │ ├── admin_topnav.php # Dark theme admin navigation
│ │ ├── ROADMAP.md # Future development ideas
│ │ └── AI_INTEGRATION.md # AI integration architecture guide
│ └── [your-app]/ # Your application code
├── login/ # Authentication pages
│ ├── index_cont.php # Login controller
│ ├── index_form.php # Login form
│ ├── new_user.php # Registration
│ ├── dashboard.php # User dashboard
│ ├── change_password.php # Password change
│ └── logout.php # Logout handler
├── skins/
│ └── powerpulse/ # Default theme
│ ├── layout.php # Main layout (parametric topnav support)
│ ├── head.php # HTML head with dynamic title
│ ├── sidebar.php # Sidebar navigation
│ ├── topnav.php # Standard top navigation
│ ├── admin_topnav.php # Admin navigation (dark theme)
│ └── scripts.php # Footer scripts
├── word_template/ # Word document templates for PHPWord
├── pdf_doc/ # Generated PDF files directory
├── logs/ # Application logs
│ ├── php_debug.log # PHP errors
│ ├── db_debug.log # Database queries
│ ├── renderer_errors.log # Template errors
│ └── deploy.log # Deployment activity
├── DEPLOYMENT.md # GitHub webhook deployment guide
└── vendor/ # Composer dependencies
Using Floe as a Template
1. Starting a New Project
bash
git clone https://github.com/kkassovic/Floe.git my-new-project
cd my-new-project
rm -rf .git
git init
git add .
git commit -m "Initial commit from Floe template"
composer require phpmailer/phpmailer twilio/sdk vlucas/phpdotenv
cp config/.env.example config/.env
Create your app directory:
mkdir -p app/myapp
Create a controller:
php
// app/myapp/products_controller.php
// Get database connection
$db = Database::instance('default');
$pdo = $db->getConnection();
// Your business logic
$stmt = $pdo->query("SELECT * FROM products");
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Render view
$renderer = new Renderer();
$renderer->setLayout(__DIR__ . '/../../skins/powerpulse/layout.php');
$content = $renderer->render(__DIR__ . '/products_view.php', [
'products' => $products,
'title' => 'Products List', // Browser tab title
'topnavFile' => '/app/floe/admin_topnav.php' // Optional: custom admin topnav
]);
echo $content;
Create a view:
Products
ID
Name
Price
= htmlspecialchars($product['id']) ?>
= htmlspecialchars($product['name']) ?>
= htmlspecialchars($product['price']) ?>
Register the route:
php
// routes.php
return [
// Your routes
['/products', __DIR__ . '/app/myapp/products_controller.php'],
// Floe framework routes
['/floe/users', __DIR__ . '/app/floe/users_controller.php'],
// ... other routes
];
Remove admin utilities (optional):
// routes.php - Comment out Floe utilities you don't need
return [
// ['/floe/db-schema', __DIR__ . '/app/floe/db_schema_controller.php'],
// ['/floe/users', __DIR__ . '/app/floe/users_controller.php'],
// Keep only what you need or remove all /floe/* routes
];
Customize the theme:
bash
cp -r skins/powerpulse skins/mytheme
$renderer->setLayout(__DIR__ . '/../../skins/mytheme/layout.php');
Add custom middleware:
// front_cont.php - After LOGIN GUARD section
// Add your custom logic here
if ($someCondition) {
// Your middleware logic
}
4. Database Schema Management
Extend the schema:
sql
-- Create your tables in a separate file: app/myapp/schema.sql
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price DECIMAL(10,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Import your schema
mysql -u username -p database < app/myapp/schema.sql
Or use the built-in schema extractor:
1. Go to /floe/db-schema
2. Export current schema
3. Edit the exported file
4. Re-import when needed
Require login for your pages:
-- Option 1: Make page public (no login required)
INSERT INTO public_pages (path_pattern, description) VALUES
('/products', 'Public product listing');
-- Option 2: Require login but allow all users (default behavior)
-- Don't add to public_pages, don't add to page_permissions
-- Option 3: Restrict to specific users
INSERT INTO page_permissions (user_id, path_pattern) VALUES
(1, '/products'), -- User 1 can access
(2, '/products'); -- User 2 can access
Check authentication in controllers:
php
// Check if user is logged in
if (!isset($_SESSION['authenticated'])) {
header('Location: /login/');
exit;
}
// Get current user info
$userId = $_SESSION['user_id'];
$email = $_SESSION['email'];
$firstName = $_SESSION['first_name'];
Protect your admin area:
env-- Only allow specific users to access /admin/* pages INSERT INTO page_permissions (user_id, path_pattern) VALUES (1, '/admin/*'), (2, '/admin/reports/*'); Use the Access Control Manager: 1. Go to/floe/access-control2. Select user and path pattern 3. Click "Add Permission".env7. Email Configuration
Configure SMTP in
:
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-password
EMAIL_FROM=your-email@gmail.com
EMAIL_ENCRYPTION=tls
Send emails using Mailer:
phprequire_once __DIR__ . '/floe/Mailer.php'; $mailer = new EmailWrap(); $mailer->setRecipients(['user@example.com']); $mailer->setSubject('Test Email'); $mailer->setBody('Email body content'); $result = $mailer->send(); Create email templates: 1. Go to/floe/samples/email-builder2. Design your email with the WYSIWYG editor 3. Insert PHP variables (e.g.,{{$firstName}},{{$email}}) 4. Add styled buttons using the button builder 5. Save template to databaseUse email templates in code:
// Load template from database
$db = Database::instance('default');
$pdo = $db->getConnection();
$stmt = $pdo->prepare("SELECT content, subject FROM email_templates WHERE template_name = ?");
$stmt->execute(['welcome_email']);
$template = $stmt->fetch(PDO::FETCH_ASSOC);
// Replace variables
$variables = [
'{{$firstName}}' => $user['first_name'],
'{{$email}}' => $user['email'],
'{{$date}}' => date('F j, Y')
];
$emailContent = str_replace(
array_keys($variables),
array_values($variables),
$template['content']
);
// Send email
$mailer = new Mailer();
$mailer->sendEmail(
to: $user['email'],
subject: $template['subject'],
body: $emailContent,
isHTML: true
);
See EMAIL_TEMPLATES.md for full documentation.
Security checklist:
1. Disable debug mode
front_cont.php
$logErrors = false;
ini_set('display_errors', '0');
Renderer.php
Renderer::setupDebug(FALSE);
2. Secure .env file
chmod 600 config/.env
3. Remove development utilities (optional)
rm -rf app/floe/
4. Set up HTTPS
Update .env
EMAIL_ENCRYPTION=tls
5. Configure session security
Already set in Auth.php with secure cookies
6. Set strong passwords in .env
7. Regular backups of database
8. Monitor logs/ directory
Configuration Reference
Session Lifetime (.env)
env
SESSION_LIFETIME=2592000 # 30 days (default)
SESSION_LIFETIME=86400 # 1 day
SESSION_LIFETIME=604800 # 1 week
Required tables:
- User accounts - Session storage - Password reset tokens - Access control - Pages that don't require login - Email sending logs - User action tracking and audit trail - Saved email templates with subject and contentOptional tables:
- Demo table (can be removed)Routes are defined in routes.php as an array:
phpreturn [ ['path', 'controller_file_path'], ['/about', __DIR__ . '/app/about/controller.php'], ];page_permissionsAccess Control Patterns
Wildcard patterns in:/floe/*- All pages under /floe//admin/*- All admin pages/api/v1/*- All API v1 endpoints/products- Specific single page/floe/samples/email-builderAdvanced Features
Email Template Builder
Rich HTML email editor with database storage (): Features:{{$firstName}}Quill WYSIWYG Editor - Full formatting toolbar (headers, fonts, colors, lists, alignment) PHP Variables - 15 predefined placeholders ( ,{{$email}},{{$date}}, etc.)email_templatesButton Builder - Email-compatible buttons with 7 color styles and 3 sizes Emoji Picker - 300+ emojis organized by category Live Preview - Real-time rendering of your email Database Storage - Templates saved to tableSubject Management - Subject line saved with template Quick Templates - Blank, Basic, Welcome, Newsletter starters Usage:
// Load template from database
$stmt = $pdo->prepare("SELECT content, subject FROM email_templates WHERE template_name = ?");
$stmt->execute(['welcome_email']);
$template = $stmt->fetch(PDO::FETCH_ASSOC);
// Replace variables
$emailContent = str_replace(
['{{$firstName}}', '{{$email}}'],
[$user['first_name'], $user['email']],
$template['content']
);
// Send
$mailer->sendEmail(to: $user['email'], subject: $template['subject'], body: $emailContent);
See EMAIL_TEMPLATES.md for complete documentation.
Comprehensive audit trail system (/floe/activity-log):
Automatic Logging:
Manual Logging:
phprequire_once __DIR__ . '/../../floe/ActivityLogger.php'; ActivityLogger::log('user_created', 'New user registered: john@example.com', $userId, $email); ActivityLogger::logUserCreated($userId, $email, $adminId); ActivityLogger::logUserUpdated($userId, $email, $adminId); Features:activity_logColor-coded actions (login=success, logout=secondary, failed=danger) DataTables with export capabilities Clear old logs (30+ days) Auto-creates tableParametric Navigation System
The framework supports custom top navigation per page:
// Use standard light theme navigation (default)
$content = $renderer->render(__DIR__ . '/view.php', [
'title' => 'My Page'
// topnavFile not specified, defaults to /skins/powerpulse/topnav.php
]);
// Use admin dark theme navigation
$content = $renderer->render(__DIR__ . '/view.php', [
'title' => 'Admin Panel',
'topnavFile' => '/app/floe/admin_topnav.php'
]);
Navigation files:
- Light theme, conditional links (Home, Dashboard, Login/Logout) - Dark theme with Admin Tools dropdownAll controllers pass a title parameter for browser tab titles:
php$content = $renderer->render(__DIR__ . '/view.php', [ 'title' => 'User Management' // Appears in browser tab ]); // Defaults to "Floe application" if not providedDROP IF EXISTSDatabase Schema Export
Export complete database schema including tables AND views:Separate sections for tables and views statements for safe re-importCREATE OR REPLACE VIEWColumn definitions with types and constraints Index definitions View definitions with /floe/db-schemaAccess via
or use Database class:
$db = Database::instance('default');
// Schema export logic in app/floe/db_schema_controller.php
for PHP errors for database queries for template errorssql$db = Database::instance('default', true); // Enable debug mode $result = $db->fetch("SELECT * FROM users WHERE id = ?", [1]);app/yourapp/page_controller.phpCreating New Pages
1. Create controller in2. Create view inapp/yourapp/page_view.php3. Register route inroutes.php4. Configure access (public_pages or page_permissions if needed)app/floe/sample_table_view.phpDataTables Integration
The framework includes DataTables 1.13.7 with extensions. Seefor examples:https://cdn.datatables.net/plug-ins/1.13.7/i18n/sk.jsonSearchPanes for filtering Export buttons (CSV, Excel, PDF) Responsive tables Custom date formatting Slovak localization via CDN: app/floe/sample_pivot_view.phpPivotTable.js Integration
Interactive data analysis and visualization. See:app/floe/word_generator_controller.phpDrag-and-drop interface for creating custom reports Multiple renderers: Table, Heatmap, Bar Chart, Line Chart, Area Chart D3.js v3.5.17 for visualizations C3.js for chart rendering Data transformations (date splitting, field mapping) Color scale generators for heatmaps PHPWord Document Generation
Generate Word documents from templates. See:${name}Variable replacement ( ,${email},${date},${content})/app/mobile/Image insertion with aspect ratio support Template validation (ZIP archive check) Pilsner Mobile App
The Pilsner dedication app () demonstrates a complete mobile-first PWA implementation with client-side image conversion.pilsner.svgFeatures
Custom SVG Generation: Creates personalized dedications from template Font Embedding: Solitreo font embedded as base64 in SVG Multi-line Text: Automatic text wrapping (max 20 chars/line, 4 lines) Client-Side Conversion: SVG → PNG using HTML5 Canvas API Android Compatibility: Ensures images work in Android gallery Database Storage: Stores SVG in MEDIUMBLOB with metadata PWA Support: Mobile-optimized with custom bottom navigation Web Share API: Native sharing on mobile devices High Resolution: 2578×3882 pixel output (3x original, ~300 DPI) Architecture
Client-Side Conversion Everywhere:No server-side dependencies (ImageMagick, rsvg-convert, Imagick) Works on all platforms (Docker, DigitalOcean, any hosting) Universal browser support (Canvas API) High-quality PNG output (2578×3882px, ~300 DPI) Reduced server load and storage footprint How It Works: 1. User enters dedication text 2. Server generates custom SVG fromtemplate 3. SVG stored in database (compressed, ~250KB) 4. SVG served to browser for display 5. On download/share: JavaScript detects image format 6. If SVG: Canvas API converts to PNG (~500KB-1MB) 7. PNG saved/shared to Android gallery Benefits:app/mobile/dedication_controller.php✅ Universal compatibility (all platforms, all browsers) ✅ Android gallery support guaranteed ✅ No platform-specific dependencies ✅ Smaller database storage (SVG compressed) ✅ Reduced server CPU usage ✅ Consistent behavior everywhere Files
- Main controller (SVG generation)app/mobile/dedication_view.php- PWA view with Canvas conversionapp/mobile/dedication_image_controller.php- Serves images from databaseword_template/pilsner.svg- SVG template with embedded logoCLIENT_SIDE_CONVERSION.md- Complete technical documentationDatabase Schema
CREATE TABLE dedications (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT(11) DEFAULT NULL,
dedication_text VARCHAR(100) NOT NULL,
image_data MEDIUMBLOB NOT NULL COMMENT 'SVG image data',
svg_path VARCHAR(255) DEFAULT NULL,
image_width INT(11) DEFAULT 859,
image_height INT(11) DEFAULT 1294,
file_size INT(11) DEFAULT NULL,
mime_type VARCHAR(50) DEFAULT 'image/svg+xml',
ip_address VARCHAR(45) DEFAULT NULL,
user_agent VARCHAR(255) DEFAULT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
Client-Side Conversion (JavaScript):
// Convert SVG to PNG using Canvas API
function convertToPNG(svgUrl) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = function() {
// Create high-resolution canvas (3x original for quality)
const targetWidth = 2578; // 3x 859
const targetHeight = 3882; // 3x 1294
const canvas = document.createElement('canvas');
canvas.width = targetWidth;
canvas.height = targetHeight;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#FFFFFF'; // White background
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
canvas.toBlob(resolve, 'image/png', 1.0);
};
img.onerror = reject;
img.src = svgUrl;
});
}
Automatic Format Detection:
javascript
async function downloadImage(imageUrl, dedicationText) {
const response = await fetch(imageUrl);
const contentType = response.headers.get('Content-Type');
if (contentType.includes('svg')) {
// Convert to PNG for Android compatibility
showToast('Konvertujem obrázok...', 'info');
const blob = await convertToPNG(imageUrl);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = prianie_${sanitizeFilename(dedicationText)}.png;
a.click();
}
}
Canvas API works on:
Works on all platforms without modifications:
See CLIENT_SIDE_CONVERSION.md for complete documentation.
directoryModern file upload with image optimization. See app/floe/sample_form_view.php:
Upload and import Excel files to database. See app/floe/sample_excel_import_controller.php:
Upload files to S3-compatible object storage. See app/floe/sample_s3_upload_controller.php:
Automatic deployment from GitHub. See DEPLOYMENT.md and app/floe/deploy_controller.php:
)Beautiful alert dialogs. See app/floe/sample_alerts_view.php:
"Headers already sent" error:
(check for BOM, whitespace)Session not persisting:
in .envAccess denied (403):
table insteadRoutes not working:
is workingThis framework is provided as-is for use as a template. Modify as needed for your projects.
For issues, questions, or contributions, please refer to the documentation files in /floe/*.md and /app/floe/*.md:
Framework Documentation:
- Authentication system - Database layer - Public page management - Email system - Template rendering - Routing systemApplication Documentation:
- Future development ideas and prioritiesBuilt with: