-
Notifications
You must be signed in to change notification settings - Fork 2
App
The App class is the core of the Webrium framework, providing essential functionality for application initialization, autoloading, environment management, localization, request handling, and comprehensive CORS security.
- Installation
- Basic Usage
- Application Initialization
- Request Handling
- Environment Variables
- Localization
- CORS Management
- Caching
- Complete Examples
- API Reference
- Security Guidelines
The App class is the core of the Webrium framework and is automatically available.
use Webrium\App;require 'vendor/autoload.php';
use Webrium\App;
// Initialize application
App::initialize(__DIR__);
// Your application code here
// Run application
App::run();// Initialize with root directory
App::initialize(__DIR__);This method:
- Sets the application root path
- Registers the autoloader
- Loads helper functions
- Enforces URL standards
$rootPath = App::getRootPath();
// Returns: /var/www/html/myapp// Get all input data
$data = App::input();
// Works with: GET, POST, PUT, DELETE, JSON
// Get specific field
$username = App::input('username');
// With default value
$page = App::input('page', 1);Supported Content Types:
- GET parameters (
$_GET) - POST form data (
$_POST) - JSON payloads (automatically parsed)
- PUT/DELETE request bodies
// Return JSON
App::returnData(['status' => 'success', 'data' => $results]);
// With custom status code
App::returnData(['error' => 'Not found'], 404);
// Return plain text
App::returnData('Hello World');Create a .env file in your project root:
APP_ENV=production
DB_HOST=localhost
DB_NAME=myapp
DB_USER=root
DB_PASS=secret
API_KEY=your-api-key-here
DEBUG=false// Get environment variable
$dbHost = App::env('DB_HOST');
// With default value
$debug = App::env('DEBUG', false);
// Check environment
if (App::env('APP_ENV') === 'production') {
// Production-specific code
}Supported Values:
-
true/false(converted to boolean) -
null(converted to null) - Numbers (kept as strings or converted)
- Quoted strings (quotes removed)
// Set locale
App::setLocale('en');
App::setLocale('fa');
App::setLocale('es');$locale = App::getLocale();
// Returns: 'en'
// Check locale
if (App::isLocale('en')) {
// English locale
}Create language files in langs/{locale}/ directory:
langs/en/messages.php:
<?php
return [
'welcome' => 'Welcome to our site',
'hello_name' => 'Hello, :name!',
'items_count' => 'You have :count items'
];langs/fa/messages.php:
<?php
return [
'welcome' => 'به سایت ما خوش آمدید',
'hello_name' => 'سلام، :name!',
'items_count' => 'شما :count مورد دارید'
];// Simple translation
$text = App::trans('messages.welcome');
// Returns: "Welcome to our site"
// With replacements
$greeting = App::trans('messages.hello_name', ['name' => 'John']);
// Returns: "Hello, John!"
$count = App::trans('messages.items_count', ['count' => 5]);
// Returns: "You have 5 items"Cross-Origin Resource Sharing (CORS) is a security mechanism that allows or restricts web applications running at one origin (domain) to access resources from a different origin.
An origin consists of:
- Protocol (http/https)
- Domain (example.com)
- Port (80, 443, 8080, etc.)
Examples:
-
https://example.com✓ Origin -
https://app.example.com✓ Different origin -
https://example.com:8080✓ Different origin (different port)
Without CORS, browsers block requests from:
Frontend: https://app.example.com
↓ (blocked by browser)
API: https://api.example.com
With proper CORS configuration:
Frontend: https://app.example.com
↓ (allowed)
API: https://api.example.com
1. Open CORS (Wildcard *)
// ❌ DANGEROUS - Allows any website to access your API
App::corsMiddleware(['*']);Risk: Any malicious website can make requests to your API, potentially stealing user data or performing unauthorized actions.
2. Credentials with Wildcard
// ❌ SECURITY VIOLATION - Will trigger error
App::corsMiddleware(['*'], [
'allow_credentials' => true // Cannot use with wildcard
]);Risk: Browsers prohibit this combination as it would allow any site to make authenticated requests.
3. Overly Permissive Origins
// ❌ BAD - Too permissive
App::corsMiddleware([
'http://localhost:3000', // Development only
'https://untrusted-site.com' // Unknown third party
]);1. Explicit Origin Whitelist
// ✓ GOOD - Explicit trusted origins only
App::corsMiddleware([
'https://myapp.com',
'https://admin.myapp.com',
'https://mobile.myapp.com'
]);2. Wildcard Subdomains (Careful Use)
// ✓ ACCEPTABLE - For your own subdomains
App::corsMiddleware([
'https://*.myapp.com' // Only your subdomains
]);3. Environment-Based Configuration
// ✓ BEST - Different config per environment
$allowedOrigins = App::env('APP_ENV') === 'development'
? ['http://localhost:3000', 'http://localhost:8080']
: ['https://myapp.com', 'https://admin.myapp.com'];
App::corsMiddleware($allowedOrigins);App::corsMiddleware([
'https://example.com'
]);App::corsMiddleware([
'https://example.com',
'https://app.example.com'
], [
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
'allowed_headers' => ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'Origin'],
'allow_credentials' => true, // Allow cookies/auth
'max_age' => 86400, // Cache preflight for 24 hours
'expose_headers' => ['X-Total-Count', 'X-Page-Count']
]);| Option | Type | Default | Description | Security Impact |
|---|---|---|---|---|
allowed_origins |
array | [] |
List of allowed origin URLs | HIGH - Controls who can access |
allowed_methods |
array | ['GET', 'POST', ...] |
HTTP methods allowed | MEDIUM - Limit to needed methods only |
allowed_headers |
array | ['Content-Type', ...] |
Headers allowed in requests | MEDIUM - Only allow necessary headers |
allow_credentials |
bool | false |
Allow cookies/authentication | HIGH - Enable only for trusted origins |
max_age |
int | 86400 |
Preflight cache duration (seconds) | LOW - Performance optimization |
expose_headers |
array | [] |
Headers exposed to client | LOW - Allow client to read headers |
Use Case: Open API accessible from any website.
<?php
require 'vendor/autoload.php';
use Webrium\App;
use Webrium\Route;
App::initialize(__DIR__);
// ⚠️ Use with caution - only for truly public APIs
App::corsMiddleware(['*']);
Route::get('/api/public/data', function() {
App::returnData([
'data' => 'Public information',
'timestamp' => time()
]);
});
App::run();Security Considerations:
- ✓ No sensitive data exposed
- ✓ No authentication required
- ✓ Rate limiting recommended
- ✓ Input validation essential
Use Case: React/Vue/Angular app on different domain/subdomain.
<?php
require 'vendor/autoload.php';
use Webrium\App;
use Webrium\Route;
App::initialize(__DIR__);
// Frontend on different domain
App::corsMiddleware([
'https://app.mysite.com'
], [
'allow_credentials' => true, // Allow cookies for authentication
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE'],
'allowed_headers' => ['Content-Type', 'Authorization']
]);
Route::get('/api/user/profile', function() {
// Check authentication
$token = \Webrium\Header::getBearerToken();
if (!$token) {
App::returnData(['error' => 'Unauthorized'], 401);
}
// Return user data
App::returnData(['user' => getUserData($token)]);
});
App::run();Security Considerations:
- ✓ Explicit origin whitelist
- ✓ Authentication required
- ✓ Credentials enabled only for trusted origin
- ✓ Validate tokens on every request
Use Case: Admin panel, mobile app, and public website sharing one API.
<?php
require 'vendor/autoload.php';
use Webrium\App;
use Webrium\Route;
App::initialize(__DIR__);
// Multiple trusted origins
App::corsMiddleware([
'https://mysite.com', // Public website
'https://admin.mysite.com', // Admin panel
'https://mobile.mysite.com' // Mobile app
], [
'allow_credentials' => true,
'allowed_headers' => [
'Content-Type',
'Authorization',
'X-API-Key', // Custom header for API key
'X-Client-Version' // Track client versions
],
'expose_headers' => [
'X-Total-Count', // Pagination
'X-Rate-Limit' // Rate limit info
]
]);
// Different routes for different clients
Route::get('/api/public/articles', function() {
// Public data - no auth needed
App::returnData(getPublicArticles());
});
Route::get('/api/admin/users', function() {
// Admin only - check role
$token = \Webrium\Header::getBearerToken();
if (!isAdmin($token)) {
App::returnData(['error' => 'Forbidden'], 403);
}
App::returnData(getAllUsers());
});
App::run();Security Considerations:
- ✓ Each origin explicitly listed
- ✓ Role-based access control
- ✓ Different endpoints for different permissions
- ✓ Client version tracking
Use Case: Different CORS settings for different environments.
<?php
require 'vendor/autoload.php';
use Webrium\App;
App::initialize(__DIR__);
// Environment-based CORS
$environment = App::env('APP_ENV', 'production');
if ($environment === 'development') {
// Development - allow local origins
App::corsMiddleware([
'http://localhost:3000', // React dev server
'http://localhost:8080', // Vue dev server
'http://127.0.0.1:3000' // Alternative localhost
], [
'allow_credentials' => true
]);
} else {
// Production - strict whitelist
App::corsMiddleware([
'https://mysite.com',
'https://app.mysite.com'
], [
'allow_credentials' => true,
'max_age' => 86400 // Cache preflight for 24 hours
]);
}
App::run();Security Considerations:
- ✓ Separate configs for dev/prod
- ✓ Never commit localhost origins to production
- ✓ Use environment variables
- ✓ Longer cache for production (better performance)
Use Case: Multiple backend services communicating.
<?php
require 'vendor/autoload.php';
use Webrium\App;
use Webrium\Route;
App::initialize(__DIR__);
// Allow other microservices
App::corsMiddleware([
'https://auth-service.internal',
'https://payment-service.internal',
'https://notification-service.internal'
], [
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE'],
'allowed_headers' => [
'Content-Type',
'Authorization',
'X-Service-Token' // Service-to-service auth
]
]);
Route::post('/api/internal/process', function() {
// Verify service token
$serviceToken = \Webrium\Header::get('X-Service-Token');
if (!verifyServiceToken($serviceToken)) {
App::returnData(['error' => 'Unauthorized service'], 403);
}
// Process request
App::returnData(['status' => 'processed']);
});
App::run();Security Considerations:
- ✓ Internal domains only
- ✓ Service-to-service authentication
- ✓ Network-level security (VPC/firewall)
- ✓ Token rotation strategy
Use Case: SaaS application with customer subdomains.
<?php
require 'vendor/autoload.php';
use Webrium\App;
App::initialize(__DIR__);
// Allow all subdomains
App::corsMiddleware([
'https://*.myapp.com' // customer1.myapp.com, customer2.myapp.com, etc.
], [
'allow_credentials' => true,
'allowed_headers' => [
'Content-Type',
'Authorization',
'X-Tenant-ID' // Multi-tenancy
]
]);
Route::get('/api/tenant/data', function() {
$tenantId = \Webrium\Header::get('X-Tenant-ID');
// Validate tenant has access
if (!validateTenantAccess($tenantId)) {
App::returnData(['error' => 'Forbidden'], 403);
}
App::returnData(getTenantData($tenantId));
});
App::run();Security Considerations:
- ✓ Wildcard only for your own domain
- ✓ Tenant isolation required
- ✓ Validate tenant in every request
- ✓ Log cross-tenant access attempts
Use Case: Native mobile app and web application.
<?php
require 'vendor/autoload.php';
use Webrium\App;
use Webrium\Route;
App::initialize(__DIR__);
App::corsMiddleware([
'https://myapp.com', // Web app
'https://app.myapp.com', // PWA
'capacitor://localhost', // iOS Capacitor app
'http://localhost', // Android Capacitor app
'ionic://localhost' // Ionic app
], [
'allow_credentials' => true,
'allowed_headers' => [
'Content-Type',
'Authorization',
'X-Device-ID', // Device tracking
'X-App-Version' // App version
]
]);
Route::post('/api/mobile/login', function() {
$deviceId = \Webrium\Header::get('X-Device-ID');
$appVersion = \Webrium\Header::get('X-App-Version');
// Check if app version is supported
if (version_compare($appVersion, MIN_SUPPORTED_VERSION, '<')) {
App::returnData([
'error' => 'Please update your app',
'min_version' => MIN_SUPPORTED_VERSION
], 426); // Upgrade Required
}
// Process login
App::returnData(['token' => generateToken($deviceId)]);
});
App::run();Security Considerations:
- ✓ Include mobile-specific origins
- ✓ Version checking
- ✓ Device fingerprinting
- ✓ Force updates for critical security patches
- Use Explicit Whitelists in Production
// ✓ GOOD
App::corsMiddleware([
'https://myapp.com',
'https://admin.myapp.com'
]);- Enable Credentials Only When Needed
// ✓ GOOD - Only for authenticated requests
App::corsMiddleware(['https://app.myapp.com'], [
'allow_credentials' => true
]);- Limit HTTP Methods
// ✓ GOOD - Only allow necessary methods
App::corsMiddleware(['https://app.myapp.com'], [
'allowed_methods' => ['GET', 'POST'] // Not PUT, DELETE if not needed
]);- Use Environment Variables
// ✓ GOOD
$origins = explode(',', App::env('CORS_ALLOWED_ORIGINS'));
App::corsMiddleware($origins);- Validate on Every Request
// ✓ GOOD - Use corsMiddleware early
App::initialize(__DIR__);
App::corsMiddleware($origins); // Before routing
App::run();- Log Rejected Origins
// ✓ GOOD - Monitor suspicious activity
if (!App::isOriginAllowed(\Webrium\Url::origin())) {
error_log('Blocked CORS request from: ' . \Webrium\Url::origin());
}- Never Use Wildcard in Production (Unless Truly Public)
// ❌ BAD
App::corsMiddleware(['*']);- Don't Enable Credentials with Wildcard
// ❌ WILL FAIL
App::corsMiddleware(['*'], [
'allow_credentials' => true
]);- Don't Include Development Origins in Production
// ❌ BAD - localhost in production
App::corsMiddleware([
'https://myapp.com',
'http://localhost:3000' // Should not be in production
]);- Don't Allow All Methods
// ❌ BAD - Unnecessary methods
App::corsMiddleware($origins, [
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD', 'TRACE']
]);- Don't Trust Origin Header Blindly
// ❌ BAD - Still validate authentication
Route::post('/api/data', function() {
// Even if origin is allowed, verify auth token
$token = \Webrium\Header::getBearerToken();
if (!$token) {
App::returnData(['error' => 'Unauthorized'], 401);
}
// ...
});// Basic usage
App::enableCors(['https://example.com']);
// With config
App::enableCors(['https://example.com'], [
'allow_credentials' => true
]);
// Current domain only
App::enableCors(); // Allows current domain// Enforce CORS with validation
App::corsMiddleware([
'https://example.com',
'https://app.example.com'
]);
// With config and custom error code
App::corsMiddleware($origins, [
'allow_credentials' => true
], 403);// Advanced configuration
App::configureCors([
'allowed_origins' => ['https://example.com'],
'allowed_methods' => ['GET', 'POST'],
'allowed_headers' => ['Content-Type'],
'allow_credentials' => false,
'max_age' => 3600,
'expose_headers' => []
]);// Set allowed origins
App::setCorsOrigins(['https://example.com']);
// Add origin
App::addCorsOrigin('https://new-domain.com');// Check if origin is allowed
if (App::isOriginAllowed()) {
// Origin is in whitelist
}
// Check specific origin
if (App::isOriginAllowed('https://example.com')) {
// Specific origin allowed
}// Get allowed origins
$origins = App::getAllowedOrigins();
// Get full config
$config = App::getCorsConfig();
// Check if CORS is enabled
if (App::isCorsEnabled()) {
// CORS is active
}// Disable browser caching
App::disableCache();This sets:
Cache-Control: no-store, no-cache, must-revalidate, max-age=0Pragma: no-cache
Useful for:
- Dynamic content
- Sensitive data
- APIs with changing data
<?php
require 'vendor/autoload.php';
use Webrium\App;
use Webrium\Route;
use Webrium\Header;
// Initialize
App::initialize(__DIR__);
// Set locale based on header
$locale = Header::get('Accept-Language', 'en');
App::setLocale(substr($locale, 0, 2));
// CORS for frontend
App::corsMiddleware([
'https://myapp.com',
'https://app.myapp.com'
], [
'allow_credentials' => true,
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE'],
'expose_headers' => ['X-Total-Count']
]);
// Authentication middleware
Route::middleware(function() {
$token = Header::getBearerToken();
if (!$token) {
App::returnData(['error' => 'Unauthorized'], 401);
}
// Validate token...
});
// Routes
Route::get('/api/users', function() {
$page = App::input('page', 1);
$users = getUsers($page);
Header::set('X-Total-Count', $users['total']);
App::returnData($users);
});
Route::post('/api/users', function() {
$data = App::input();
$user = createUser($data);
App::returnData($user, 201);
});
Route::put('/api/users/:id', function($id) {
$data = App::input();
$user = updateUser($id, $data);
App::returnData($user);
});
Route::delete('/api/users/:id', function($id) {
deleteUser($id);
App::returnData(['message' => 'Deleted'], 204);
});
App::run();<?php
require 'vendor/autoload.php';
use Webrium\App;
use Webrium\Route;
use Webrium\Header;
App::initialize(__DIR__);
// Environment-based CORS
$environment = App::env('APP_ENV', 'production');
$origins = $environment === 'production'
? ['https://*.myapp.com']
: ['http://localhost:3000'];
App::corsMiddleware($origins, [
'allow_credentials' => true,
'allowed_headers' => [
'Content-Type',
'Authorization',
'X-Tenant-ID'
]
]);
// Tenant validation middleware
Route::middleware(function() {
$tenantId = Header::get('X-Tenant-ID');
if (!$tenantId) {
App::returnData(['error' => 'Tenant ID required'], 400);
}
// Validate tenant exists and is active
if (!isActiveTenant($tenantId)) {
App::returnData(['error' => 'Invalid tenant'], 403);
}
// Store tenant context
define('CURRENT_TENANT', $tenantId);
});
// Tenant-scoped routes
Route::get('/api/tenant/settings', function() {
$settings = getTenantSettings(CURRENT_TENANT);
App::returnData($settings);
});
Route::post('/api/tenant/data', function() {
$data = App::input();
$result = saveTenantData(CURRENT_TENANT, $data);
App::returnData($result);
});
App::run();<?php
require 'vendor/autoload.php';
use Webrium\App;
use Webrium\Route;
use Webrium\Header;
App::initialize(__DIR__);
// Public API - open CORS
App::corsMiddleware(['*']);
// Rate limiting middleware
Route::middleware(function() {
$apiKey = Header::getApiKey();
$ip = \Webrium\Url::clientIp();
$identifier = $apiKey ?? $ip;
$limit = $apiKey ? 1000 : 100; // Higher limit for API keys
$remaining = checkRateLimit($identifier, $limit);
Header::setMultiple([
'X-Rate-Limit' => (string)$limit,
'X-Rate-Limit-Remaining' => (string)$remaining,
'X-Rate-Limit-Reset' => (string)(time() + 3600)
]);
if ($remaining <= 0) {
App::returnData([
'error' => 'Rate limit exceeded',
'retry_after' => 3600
], 429);
}
});
// Public endpoints
Route::get('/api/public/data', function() {
$data = getPublicData();
// Cache for 5 minutes
Header::cache(300);
App::returnData($data);
});
App::run();| Method | Description |
|---|---|
initialize($dir) |
Initialize framework with root directory |
getRootPath() |
Get application root path |
run() |
Start application (initialize debugging and routing) |
| Method | Description |
|---|---|
input($key, $default) |
Get request input data |
returnData($data, $statusCode) |
Return response data |
| Method | Description |
|---|---|
env($key, $default) |
Get environment variable |
| Method | Description |
|---|---|
setLocale($locale) |
Set application locale |
getLocale() |
Get current locale |
isLocale($locale) |
Check if locale matches |
trans($key, $replacements) |
Get translation |
| Method | Description |
|---|---|
enableCors($origins, $config) |
Enable CORS with configuration |
corsMiddleware($origins, $config, $errorCode) |
CORS middleware with validation |
configureCors($config) |
Configure CORS settings |
setCorsOrigins($origins) |
Set allowed origins |
addCorsOrigin($origins) |
Add origin to whitelist |
isOriginAllowed($origin) |
Check if origin is allowed |
getAllowedOrigins() |
Get allowed origins list |
getCorsConfig() |
Get CORS configuration |
isCorsEnabled() |
Check if CORS is enabled |
| Method | Description |
|---|---|
disableCache() |
Disable browser caching |
- Use explicit origin whitelists (no
*in production) - Enable credentials only for trusted origins
- Validate authentication on every request
- Use HTTPS in production
- Implement rate limiting
- Log and monitor blocked requests
- Use environment-based configuration
- Validate and sanitize all input
- Keep dependencies updated
- Use security headers (
Header::security())
- Never use wildcard with credentials
- List only trusted origins
- Limit allowed HTTP methods
- Restrict allowed headers
- Use separate configs for dev/prod
- Validate origin header server-side
- Implement authentication even with CORS
- Monitor and log rejected requests
- Use network-level security (firewall)
- Regular security audits
-
Trusting CORS alone for security
- ❌ CORS is not authentication
- ✓ Always validate tokens/sessions
-
Using wildcard in production
- ❌ Opens API to all websites
- ✓ Use explicit whitelist
-
Forgetting about other attack vectors
- ❌ Only focusing on CORS
- ✓ Implement CSRF, XSS protection
-
Not validating input
- ❌ Trusting client data
- ✓ Validate and sanitize all input
# Test preflight request
curl -X OPTIONS http://api.example.com/endpoint \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Content-Type" \
-v
# Test actual request
curl -X POST http://api.example.com/endpoint \
-H "Origin: https://app.example.com" \
-H "Content-Type: application/json" \
-d '{"test":"data"}' \
-v// Test from browser console
fetch('https://api.example.com/endpoint', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include', // If credentials enabled
body: JSON.stringify({test: 'data'})
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('CORS Error:', error));1. "No 'Access-Control-Allow-Origin' header is present"
- Cause: CORS not configured or origin not whitelisted
-
Fix: Add origin to
corsMiddleware()
2. "Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'"
- Cause: Using wildcard with credentials
- Fix: Use explicit origins with credentials
3. "Method DELETE is not allowed by Access-Control-Allow-Methods"
- Cause: Method not in allowed list
-
Fix: Add method to
allowed_methodsconfig
4. "Request header field Authorization is not allowed"
- Cause: Header not in allowed list
-
Fix: Add header to
allowed_headersconfig