The Request class gives you a clean interface to everything the framework knows about the current incoming HTTP request: who made it, how, and what they sent. It is the single place in JiFramework for reading client IP addresses, request headers, the raw body, auth tokens, and environment variables.
- Class:
JiFramework\Core\Utilities\Request - Access:
$app->request - Lifecycle: eager-loaded — instantiated immediately inside
App::__construct(), before any lazy component - Used internally by:
RateLimiterandAccessControlto resolve the client IP on every request
$app = new App();
$ip = $app->request->getClientIp();
$method = $app->request->getRequestMethod();
$token = $app->request->getBearerToken();
Method groups:
- IP detection —
getClientIp() - Server info —
getServerInfo(),getPhpVersion() - Request inspection —
getRequestHeaders(),getRequestMethod(),isHttps(),isAjax(),isCli(),getBody(),getBearerToken() - Environment variables —
getEnv()
getClientIp(): string
Return the client IP address for the current request. This is the single authoritative IP resolution point used across the entire framework — by the rate limiter, access control, and any direct call from application code.
Returns: string — a valid IP address (IPv4 or IPv6), or an empty string when REMOTE_ADDR is absent or not a valid IP.
Resolution order:
- If
debug_ipis set andapp_mode = development— returndebug_ip(dev override for localhost testing). - If
REMOTE_ADDRis intrusted_proxies— walkX-Forwarded-Forright-to-left and return the first non-proxy IP. - Otherwise — return
REMOTE_ADDRdirectly (the default and most common path).
Security note: REMOTE_ADDR is the actual TCP connection IP and cannot be forged by the client. X-Forwarded-For is a client-controlled header and is only read when REMOTE_ADDR matches a trusted proxy you configured. If you do not run behind a proxy, leave trusted_proxies empty — no configuration required.
$ip = $app->request->getClientIp();
// Log, pass to access control, store in audit trail, etc.
$app->logger->info('Incoming request from {ip}', ['ip' => $ip]);
Two jiconfig.php keys control how getClientIp() resolves the client IP. Both default to off — no configuration is needed for a standard single-server setup.
trusted_proxies
(array) IP addresses of trusted reverse proxies — load balancers, CDNs, or an Nginx front-end sitting in front of PHP-FPM. When REMOTE_ADDR matches one of these addresses, the real client IP is read from X-Forwarded-For (walking right-to-left to skip any intermediate proxy hops). Default: []
debug_ip
(string|null) Override the detected client IP for local development. Useful for testing rate limiting and access control on localhost where REMOTE_ADDR is always 127.0.0.1. Only honoured when app_mode = development — in production mode it is silently ignored and a warning is written to the log. Default: null
// Running behind Nginx, a load balancer, or a CDN:
'trusted_proxies' => ['127.0.0.1', '10.0.0.1'],
// Testing IP-based features on localhost:
'app_mode' => 'development',
'debug_ip' => '203.0.113.42', // RFC 5737 test range — clearly fictional
Multiple proxy hops
If your traffic passes through more than one proxy, add all of their IPs to trusted_proxies. The framework walks X-Forwarded-For from right to left and stops at the first IP that is not in the trusted list — that is the real client.
// CDN (10.0.0.3) → Load balancer (10.0.0.2) → PHP server
'trusted_proxies' => ['10.0.0.2', '10.0.0.3'],
// X-Forwarded-For: 203.0.113.42, 10.0.0.3, 10.0.0.2
// → resolved IP: 203.0.113.42
getServerInfo(): array
Return a snapshot of server-level environment data. This covers information about the web server itself, not the individual HTTP request. For request-specific data use getRequestMethod(), $app->url->path(), and $app->url->queryParam().
Returns: array with the following keys (empty string when the underlying $_SERVER key is absent):
server_software— (string) Web server identifier, e.g.Apache/2.4.57ornginx/1.25.3.server_protocol— (string) HTTP protocol version, e.g.HTTP/1.1orHTTP/2.document_root— (string) Absolute path to the web server document root.remote_addr— (string) RawREMOTE_ADDR(the TCP connection IP, before any proxy resolution). UsegetClientIp()when you want the resolved client IP.
$info = $app->request->getServerInfo();
echo $info['server_software']; // "Apache/2.4.57 (Debian)"
echo $info['server_protocol']; // "HTTP/1.1"
echo $info['document_root']; // "/var/www/html"
echo $info['remote_addr']; // "127.0.0.1" (raw TCP connection IP)
getPhpVersion(): string
Return the current PHP version string. Equivalent to calling phpversion() directly.
Returns: string — the PHP version in x.y.z format, e.g. "8.2.12".
$ver = $app->request->getPhpVersion();
echo $ver; // "8.2.12"
// Enforce a minimum version at runtime
if (version_compare($ver, '8.1.0', '<')) {
$app->abort(500, 'PHP 8.1 or higher is required.');
}
getRequestHeaders(): array
Return all HTTP headers sent with the current request as an associative array. Header names are title-cased (e.g. Content-Type, Accept-Language).
Returns: array<string, string> — header name → value pairs.
Uses getallheaders() when available (Apache, PHP-FPM). Falls back to iterating $_SERVER HTTP_* keys on other SAPIs so it works everywhere.
$headers = $app->request->getRequestHeaders();
// Case-insensitive lookup
$normalized = array_change_key_case($headers, CASE_LOWER);
$contentType = $normalized['content-type'] ?? '';
$accept = $normalized['accept'] ?? '';
// Check for a custom header
if (isset($normalized['x-api-version'])) {
$apiVersion = $normalized['x-api-version'];
}
getRequestMethod(): string
Return the HTTP method for the current request in uppercase. Returns "GET" when $_SERVER['REQUEST_METHOD'] is absent.
Returns: string — e.g. "GET", "POST", "PUT", "DELETE", "PATCH".
$method = $app->request->getRequestMethod();
switch ($method) {
case 'GET':
// return the resource
break;
case 'POST':
// create
break;
case 'PUT':
case 'PATCH':
// update
break;
case 'DELETE':
// delete
break;
default:
$app->abort(405, 'Method Not Allowed');
}
Three lightweight boolean methods that inspect the nature of the current request.
isHttps(): bool
Returns true when the current request was made over HTTPS. Handles all common setups:
- Direct SSL/TLS:
$_SERVER['HTTPS'] === 'on' - Port-based detection:
$_SERVER['SERVER_PORT'] == 443 - Reverse proxy / CDN:
X-Forwarded-Proto: https(case-insensitive)
if (!$app->request->isHttps()) {
// Redirect HTTP to HTTPS
$app->redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
}
isAjax(): bool
Returns true when the request carries the X-Requested-With: XMLHttpRequest header. jQuery, Axios, and most HTTP client libraries set this automatically. The check is case-insensitive. Note that the native Fetch API does not set this header by default.
if ($app->request->isAjax()) {
$app->json(200, ['status' => 'ok', 'data' => $result]);
} else {
// Render full HTML page
include 'views/result.php';
}
isCli(): bool
Returns true when PHP is running on the command line (PHP_SAPI === 'cli'). Useful for scripts that run both as a web request and as a cron job / CLI tool.
if ($app->request->isCli()) {
// Running as: php run-job.php
echo 'Running in CLI mode' . PHP_EOL;
} else {
// Running as a web request — HTML output is expected
header('Content-Type: text/html');
}
getBody(): string
Return the raw request body read from php://input. This is the standard way to read JSON payloads, XML, or any other non-form-encoded data sent in a POST, PUT, or PATCH request.
Returns: string — the raw body, or an empty string when there is no body (e.g. a GET request).
Note: For standard HTML form submissions (Content-Type: application/x-www-form-urlencoded or multipart/form-data), PHP already parses the data into $_POST and $_FILES. Use getBody() for JSON APIs or custom content types where PHP does not parse the body automatically.
// JSON API endpoint
if ($app->request->getRequestMethod() === 'POST') {
$raw = $app->request->getBody();
$data = json_decode($raw, true);
if (!is_array($data)) {
$app->json(400, ['error' => 'Invalid JSON body']);
}
$name = $data['name'] ?? '';
$email = $data['email'] ?? '';
// ...
}
getBearerToken(): string|null
Extract the token value from an Authorization: Bearer <token> header. Returns null when the header is absent, empty, or uses a different authentication scheme (e.g. Basic, Digest).
Returns: string|null — the bare token string, or null.
The "Bearer" scheme keyword check is case-insensitive. The token itself is returned exactly as received, with no decoding or validation applied.
$token = $app->request->getBearerToken();
if ($token === null) {
$app->json(401, ['error' => 'Authorization token required']);
}
// Verify the token (e.g. a JWT or an opaque API key)
$payload = $app->auth->verifyApiToken($token);
if ($payload === false) {
$app->json(401, ['error' => 'Invalid or expired token']);
}
Tip: On Apache, PHP may not populate $_SERVER['HTTP_AUTHORIZATION'] by default. Add the following line to your .htaccess to pass the header through:
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
getEnv(string $key, mixed $default = null): mixed
Read a server or process environment variable. Checks $_ENV first, then falls back to getenv() so it works regardless of the variables_order setting in php.ini. Returns $default when the variable is not set.
$key— (string) The environment variable name.$default— (mixed) Value to return when the variable is not set. Default:null.
Returns: mixed — the variable value, or $default.
// Read an environment variable set in .env / server config
$dbHost = $app->request->getEnv('DB_HOST', 'localhost');
$apiKey = $app->request->getEnv('STRIPE_API_KEY');
$appEnv = $app->request->getEnv('APP_ENV', 'production');
if ($apiKey === null) {
$app->logger->error('STRIPE_API_KEY environment variable is not set');
$app->abort(500, 'Payment service is not configured');
}
Tip: Store sensitive credentials (API keys, database passwords) in environment variables or a secrets manager rather than in config files. This prevents them from being accidentally committed to version control.
JSON API endpoint that requires Bearer auth
// api/orders.php
$req = $app->request;
// Only accept POST requests
if ($req->getRequestMethod() !== 'POST') {
$app->json(405, ['error' => 'Method Not Allowed']);
}
// Require a Bearer token
$token = $req->getBearerToken();
if ($token === null || !$app->auth->verifyApiToken($token)) {
$app->json(401, ['error' => 'Unauthorized']);
}
// Decode JSON body
$data = json_decode($req->getBody(), true);
if (!is_array($data)) {
$app->json(400, ['error' => 'Invalid JSON']);
}
// Process the order...
$app->json(201, ['status' => 'created', 'id' => $newOrderId]);
Unified HTML / AJAX response
// pages/search.php
$results = $app->db->table('products')->where('name', 'LIKE', '%' . $q . '%')->get();
if ($app->request->isAjax()) {
$app->json(200, ['results' => $results]);
} else {
include 'views/search.php'; // full page render
}
HTTP → HTTPS redirect
// index.php — force HTTPS in production
if (!$app->request->isHttps() && Config::$appMode === 'production') {
$app->redirect('https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
}
Audit log with full request context
$req = $app->request;
$app->logger->info('Incoming request', [
'ip' => $req->getClientIp(),
'method' => $req->getRequestMethod(),
'https' => $req->isHttps() ? 'yes' : 'no',
'ajax' => $req->isAjax() ? 'yes' : 'no',
'php' => $req->getPhpVersion(),
]);