LilaPHP

Background Workers & Queues (`Core\Task`)

Performance First

To keep your API responses under a few milliseconds (`Performance First`), never perform heavy tasks synchronously inside request routes (like sending massive emails, resizing images, or processing CSV files). `Core\Task` automatically dispatches them to background worker processes without blocking API throughput.

How `Task::dispatch()` Works Under the Hood

`Core\Task` dynamically detects your deployment environment:

  • Distributed Redis Mode (Default in Docker Prod): If Redis (`6379`) is active in `.env`, the task payload (`json`) is pushed into the `lilaphp:jobs` queue (`Redis::lPush`). Background CLI workers consume it asynchronously.
  • Standalone Fallback Mode (`proc_open` / detached process): If Redis is disabled or unavailable, `Task::dispatch()` executes a detached OS background process, instantly releasing your HTTP worker.

1. Dispatching a Task from an API Route

use Core\Task;
use Core\Response;

Task::dispatch('send_invoice_email', [
    'user_id' => 123,
    'invoice_id' => 'INV-2026-8891',
    'amount' => 149.99
]);

Response::json(['status' => 'order_placed', 'invoice_id' => 'INV-2026-8891']);

2. Creating the Job Processor (`app/jobs/*.php`)

When a job is processed, `Core\Task` automatically includes your PHP script from the `app/jobs/` folder matching the job name (e.g., `app/jobs/send_invoice_email.php`). Inside the script, `$jobName` and `$payload` are injected into scope:

<?php
use Core\Logger;

$userId = $payload['user_id'] ?? 0;
$amount = $payload['amount'] ?? 0.0;

Logger::info("Processing invoice job for User #{$userId} (${amount})...");
return true;

3. Running the Worker Process (`php cli.php task:work`)

In production or high-concurrency environments, run one or more worker daemons using our `cli.php` entry point:

# Start continuous worker daemon consuming Redis job queue
php cli.php task:work

# Run worker inside Docker container
php cli.php docker exec-php
php cli.php task:work

Anti-Malware File Upload (`Core\Upload`)

Security Shield

Handling user file uploads securely is one of the most critical parts of any web API. Core\Upload provides automated multi-layer security checks to protect your application from malicious uploads, remote code execution (RCE), MIME spoofing, and double-extension exploits.

🔍 Binary MIME Inspection

Uses PHP's finfo_file(FILEINFO_MIME_TYPE) to verify real file magic bytes, rejecting client-provided extension spoofing.

🛡️ Embedded Script Scanner

Scans initial byte chunks for embedded <?php, <?=, and <script payloads hiding inside images or PDFs.

🎲 Cryptographic Random Filenames

Generates 32-character hexadecimal filenames via bin2hex(random_bytes(16)) to prevent directory traversal or file overwrites.

📏 Strict File Size Enforcement

Enforces custom byte boundaries per route (defaults to 10 MB) before processing or moving files.

Handling File Uploads in API Routes

use Core\Request;
use Core\Response;
use Core\Upload;

Request::POST(function() {
    if (!isset($_FILES['avatar'])) {
        Response::error('No avatar file provided in upload', 422);
    }

    // 1. Process and save with allowed MIME whitelist (images only)
    $savedFilename = Upload::save($_FILES['avatar'], null, [
        'image/jpeg' => 'jpg',
        'image/png'  => 'png',
        'image/webp' => 'webp'
    ], maxSizeMax: 5 * 1024 * 1024); // 5 MB limit

    if (!$savedFilename) {
        Response::error('Invalid or malicious file detected', 400);
    }

    // 2. Return public URL or filename
    Response::json([
        'status' => 'success',
        'filename' => $savedFilename,
        'url' => '/uploads/' . $savedFilename
    ], 201);
});

Deleting Uploaded Files

use Core\Upload;

$deleted = Upload::delete('e9f8a1b2c3d4e5f678901234567890ab.webp');

Real-Time WebSockets & Redis Pub/Sub (`Core\Ws`)

Real-time Engine

LilaPHP includes a high-performance **Socket.IO style real-time engine** powered by **Workerman (`workerman/workerman`)** and **Redis Pub/Sub**. Your PHP-FPM API routes (`POST /api/items`) can broadcast messages directly to connected frontend browsers in `< 1ms` without keeping heavy FPM worker connections open!

1. Broadcasting from PHP-FPM API Routes (`Core\Ws::publish`)

use Core\Ws;
use Core\Response;

Ws::publish('item_created', [
    'id' => 105,
    'name' => 'Mechanical Keyboard',
    'price' => 129.99
], 'products_room');

Response::json(['status' => 'success', 'message' => 'Item created and broadcasted live']);

2. Frontend Client Wrapper (`public/js/ws.js`)

// Join a room
ws.join('products_room', { password: 'room_password_if_needed' });

// Listen for live events broadcasted by Core\Ws::publish or clients
ws.on('item_created', (data, room) => {
    console.log(`Live notification in room [${room}]:`, data);
});

// Emit event to others in the room (excludes sender socket)
ws.emit('chat_message', { text: 'Hello others!' }, 'products_room');

// Emit event to ALL clients in the room (including the sender socket)
ws.broadcastAll('chat_message', { text: 'Hello everyone including me!' }, 'products_room');

3. Running the WebSocket Server (`php cli.php ws:serve`)

# Start WebSocket server on port 8001
php cli.php ws:serve 8001

# Start in background daemon mode (-d)
php cli.php ws:serve 8001 -d

# Stop or restart daemon
php cli.php ws:serve stop 8001
php cli.php ws:serve restart 8001 -d

API Client & Multi-cURL Client (`Core\Http`)

HTTP Suite

Need to call external microservices, payment gateways (Stripe/PayPal), LLM APIs, or webhooks? Core\Http provides an ultra-lightweight cURL wrapper with connection pooling, automatic JSON encoding/decoding, and high-speed asynchronous batch execution via curl_multi_* without requiring Guzzle or heavy external dependencies.

1. Synchronous Requests (`Http::get` & `Http::post`)

use Core\Http;
use Core\Response;

// 1. Send GET request with headers
$response = Http::get('https://api.github.com/users/seip25', [
    'User-Agent: LilaPHP-Engine/3.0',
    'Accept: application/vnd.github.v3+json'
]);

// 2. Send POST JSON request automatically
$postResult = Http::post('https://api.stripe.com/v1/charges', [
    'amount' => 2000,
    'currency' => 'usd'
], [
    'Authorization: Bearer sk_test_xxxxxx'
]);

// Check status codes and parse JSON response directly
if ($postResult['status'] === 200) {
    Response::json(['payment' => 'success', 'data' => $postResult['json']]);
} else {
    Response::json(['error' => 'Gateway rejected transaction'], 502);
}

2. High-Speed Concurrent Batch Requests (`Http::multi`)

Execute multiple HTTP requests simultaneously in parallel TCP sockets using asynchronous curl_multi_*:

use Core\Http;
use Core\Response;

// Dispatch 3 external API calls in parallel:
$results = Http::multi([
    'weather'  => ['url' => 'https://api.weather.com/v1/current', 'method' => 'GET', 'timeout' => 5],
    'rates'    => ['url' => 'https://api.exchange.com/rates', 'method' => 'GET', 'timeout' => 5],
    'analytics'=> ['url' => 'https://analytics.internal/event', 'method' => 'POST', 'payload' => ['event' => 'page_view']]
]);

// Access each response directly by key
$weatherData = $results['weather']['json'];
$ratesData   = $results['rates']['json'];

Response::json([
    'weather' => $weatherData,
    'rates' => $ratesData
]);

Built-in Debug & Benchmark CLI Engine

CLI Suite

LilaPHP features a zero-overhead interactive Debug & Benchmark CLI Engine built into php cli.php. It enables real-time system diagnostics, debug stream inspection, and OS-level asynchronous HTTP stress testing for high concurrencies directly from your terminal.

Configuring Debug Environment (`.env`)

Debug logging to Redis is disabled by default (DEBUG_LOGGING_ENABLED=false) to guarantee zero performance overhead. Enable it in development or staging to capture live request streams:

DEBUG_LOGGING_ENABLED=false

When deploying to production via php cli.php docker prod, if DEBUG_LOGGING_ENABLED is set to true, the CLI will display an interactive warning asking for confirmation before proceeding.

Server-Side Load Test Runner (`curl_multi`)

LilaPHP features a built-in OS-level benchmark engine powered by asynchronous curl_multi_exec sockets. It executes real concurrent TCP connections and outputs live performance metrics directly to your terminal.

php cli.php benchmark --url=/api/health --concurrency=1000 --duration=30
  • Req/Sec (RPS): Exact throughput measurement.
  • Latency Percentiles: Calculates P50, P95, and P99 distribution.
  • Terminal Metrics: Live progress reporting and comprehensive summary stats.

Running High-Concurrency Benchmark Tests (Bypassing Rate Limiters)

To run synthetic load testing at high concurrencies (100, 1000, 2000, 3000, 4000) without triggering rate limiters:

  1. Set RATE_LIMIT=0 in `.env` (disables PHP rate limiter).
  2. Comment out Nginx C-level rate limiting in docker/nginx/nginx.conf:
# limit_req_zone $binary_remote_addr zone=api_limit:10m rate=60r/s;

location ^~ /api/ {
    # limit_req zone=api_limit burst=30 nodelay;
    # limit_req_status 429;

    include fastcgi_params;
    fastcgi_pass php:9000;
    ...
}
Stats in real time with cli (optional)
#Execute docker stats with cli 
php cli.php docker stats