Response
The Response class provides a fluent interface for building and sending HTTP responses.
It handles status codes, headers, cookies, content types, redirects, and common response
formats such as JSON, HTML, plain text, and XML.
The Response instance is available inside your controllers via $this->response.
All setter methods return $this, so calls can be chained before a final send().
<?php
$this->response
->set_status_code(201)
->add_header('X-Resource-Id', $id)
->set_json_content(['id' => $id])
->send();
Status Codes
Set and inspect the HTTP status code.
<?php
$this->response->set_status_code(404);
$this->response->get_status_code(); // 404
$this->response->get_status_text(); // 'Not Found'
$this->response->get_status_text(201); // 'Created'
$this->response->is_successful(); // true (2xx)
$this->response->is_redirect(); // false (3xx)
$this->response->is_client_error(); // true (4xx)
$this->response->is_server_error(); // false (5xx)
$this->response->is_error(); // true (4xx or 5xx)
$this->response->is_status(404); // true
Method |
Signature |
Description |
|---|---|---|
|
|
Set the HTTP status code |
|
|
Return the current status code |
|
|
Return the status text (e.g. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Headers
Add, remove, and inspect response headers before they are sent.
<?php
// Single header
$this->response->add_header('X-App-Version', '2.0');
// Multiple headers at once
$this->response->add_header([
'X-Frame-Options' => 'DENY',
'X-Content-Type-Options' => 'nosniff',
]);
// Read / check
$value = $this->response->get_header('X-App-Version'); // '2.0'
$this->response->has_header('X-App-Version'); // true
// Remove
$this->response->remove_header('X-App-Version');
// All headers
$headers = $this->response->get_headers();
Setting the Content-Type
Use content_type() as a shortcut instead of add_header('Content-Type', ...) directly:
<?php
$this->response->content_type('application/pdf');
$this->response->content_type('image/png', ''); // omit charset
Cache control
<?php
// Cache publicly for 1 hour
$this->response->cache(3600);
// Cache privately for 5 minutes
$this->response->cache(300, 'private');
// Disable all caching
$this->response->no_cache();
Security headers
with_security_headers() adds a sensible set of security headers in one call.
Pass an array to override individual headers:
<?php
$this->response->with_security_headers();
// Override one header while keeping the rest
$this->response->with_security_headers([
'X-Frame-Options' => 'DENY',
]);
The defaults applied are:
Header |
Default value |
|---|---|
|
|
|
|
|
|
|
|
|
|
CORS headers
<?php
// Allow all origins (default)
$this->response->with_cors();
// Specific origin with credentials
$this->response->with_cors(
'https://app.example.com', // origin
'GET, POST, DELETE', // methods
'Content-Type, Authorization, X-Api-Key', // headers
TRUE // allow credentials
);
Method |
Signature |
Description |
|---|---|---|
|
|
Add one header or an array of headers |
|
|
Remove a header by name |
|
|
Check if a header is set |
|
|
Get a single header value |
|
|
Get all queued headers |
|
|
Set |
|
|
Set cache control headers |
|
|
Disable all caching |
|
|
Add common security headers |
|
|
Add CORS headers |
Content
Set, inspect, and modify the response body.
<?php
$this->response->set_content('<p>Hello</p>');
$this->response->append_content('<p>More</p>');
$this->response->get_content(); // '<p>Hello</p><p>More</p>'
$this->response->get_content_length(); // byte length as int
$this->response->is_empty(); // false
// Typed setters (also set the matching Content-Type header)
$this->response->set_html_content('<h1>Hi</h1>');
$this->response->set_json_content(['ok' => true]);
$this->response->set_json_content($data, JSON_PRETTY_PRINT);
$this->response->set_text_content('plain text');
$this->response->set_xml_content('<root><item/></root>');
Method |
Signature |
Description |
|---|---|---|
|
|
Set the raw response body |
|
|
Return the current body |
|
|
Append to the existing body |
|
|
Body size in bytes |
|
|
|
|
|
Body + |
|
|
JSON-encode body + |
|
|
Body + |
|
|
Body + |
Sending Responses
send() flushes all queued headers, cookies, and the content body to the browser.
<?php
$this->response
->set_status_code(200)
->set_html_content('<p>OK</p>')
->send();
// Headers only — no body output
$this->response->send_headers();
Note
send_headers() is safe to call multiple times — headers are only written once.
Convenience Send Methods
These methods set the status code, Content-Type, body, and call send() in one go.
JSON
<?php
// Raw JSON
$this->response->send_json(['key' => 'value'], 200);
// Success envelope: {"success":true,"message":"...","data":{...}}
$this->response->send_json_success($user, 'User retrieved');
// Error envelope: {"success":false,"error":"..."}
$this->response->send_json_error('Not found', 404);
// Validation error (422): {"success":false,"error":"...","errors":{...}}
$this->response->send_json_validation([
'email' => 'The email field is required.',
'name' => 'The name field is required.',
]);
// Error with extra fields in the payload
$this->response->send_json_error('Rate limit exceeded', 429, [
'retry_after' => 60,
]);
Other formats
<?php
$this->response->send_html('<h1>Hello</h1>', 200);
$this->response->send_text('OK', 200);
$this->response->send_xml('<r><ok/></r>', 200);
$this->response->send_no_content(); // 204 — empty body
Semantic HTTP shortcuts
These methods send the correct status code and a JSON error/success envelope without any boilerplate:
<?php
$this->response->send_created($user, '/users/42'); // 201 + Location header
$this->response->send_unauthorized(); // 401
$this->response->send_forbidden('Insufficient role'); // 403
$this->response->send_not_found('User not found'); // 404
$this->response->send_method_not_allowed(['GET', 'POST']); // 405 + Allow header
$this->response->send_too_many_requests('Slow down', 60); // 429 + Retry-After
$this->response->send_server_error('Something went wrong'); // 500
Method |
Signature |
Status |
|---|---|---|
|
|
any |
|
|
200 |
|
|
any |
|
|
422 |
|
|
200 |
|
|
200 |
|
|
200 |
|
|
204 |
|
|
201 |
|
|
401 |
|
|
403 |
|
|
404 |
|
|
405 |
|
|
429 |
|
|
500 |
Redirects
<?php
// Temporary (302)
$this->response->redirect('/dashboard');
// Permanent (301)
$this->response->redirect_permanent('/new-url');
// After a form POST — prevents re-submission on page refresh (303)
$this->response->redirect_after_post('/users');
// Custom code
$this->response->redirect('/api/v2/users', 307);
// Back to the referring page (falls back to '/' if no referrer)
$this->response->back('/home');
Code |
Meaning |
|---|---|
301 |
Moved Permanently — browser caches the new location |
302 |
Found (temporary) — default |
303 |
See Other — correct choice after a successful POST |
307 |
Temporary Redirect — preserves the HTTP method |
308 |
Permanent Redirect — like 301 but preserves the HTTP method |
Warning
redirect(), redirect_permanent(), and redirect_after_post() all call
exit internally. Any code placed after these calls will never run.
Method |
Signature |
Description |
|---|---|---|
|
|
Redirect to a URL and exit |
|
|
301 permanent redirect |
|
|
303 redirect (Post/Redirect/Get pattern) |
|
|
Redirect to the referrer or fallback |
File Downloads & Inline Display
Force a file download:
<?php
// Download using the original filename
$this->response->download('/var/exports/report.pdf');
// Custom download filename
$this->response->download('/var/exports/report.pdf', 'Q3-Report.pdf');
// With extra headers
$this->response->download('/var/exports/report.pdf', 'Q3-Report.pdf', [
'X-Generated-By' => 'LavaLust',
]);
Display a file in the browser (inline):
Use inline() for images, PDFs, or other files the browser can render natively:
<?php
$this->response->inline('/var/uploads/photo.jpg');
$this->response->inline('/var/docs/manual.pdf', 'user-manual.pdf');
Note
Both download() and inline() stream the file in 8 KB chunks to avoid
loading the entire file into PHP memory. A 404 response is sent automatically
if the file does not exist.
Method |
Signature |
Description |
|---|---|---|
|
|
Force a file download ( |
|
|
Render a file in the browser ( |
Streaming
Use stream() to generate and send content progressively, avoiding PHP memory limits
on large responses. send_event_stream() is a convenience wrapper for Server-Sent Events.
<?php
// Stream NDJSON (one JSON object per line)
$this->response->stream(function() use ($rows) {
foreach ($rows as $row) {
echo json_encode($row) . "\n";
flush();
}
}, ['Content-Type' => 'application/x-ndjson']);
// Server-Sent Events
$this->response->send_event_stream(function() {
echo "data: " . json_encode(['time' => time()]) . "\n\n";
flush();
});
Note
stream() automatically adds Cache-Control: no-cache.
send_event_stream() additionally sets Content-Type: text/event-stream
and X-Accel-Buffering: no (disables Nginx buffering), and clears any open
output buffer before streaming begins.
Method |
Signature |
Description |
|---|---|---|
|
|
Stream content via a callable after sending headers |
|
|
SSE stream with correct headers and buffer management |
Utility
Reset the response
clear() resets the object to its initial state — useful when building responses
conditionally or between test assertions on the same instance:
<?php
$this->response->set_status_code(500)->set_content('Error');
$this->response->clear();
$this->response->get_status_code(); // 200
$this->response->get_content(); // NULL
Inspect the response as an array
to_array() returns a snapshot of the current state without triggering an HTTP send —
useful for logging or unit testing:
<?php
$this->response
->set_status_code(200)
->set_json_content(['ok' => true]);
$snapshot = $this->response->to_array();
// [
// 'status_code' => 200,
// 'status_text' => 'OK',
// 'headers' => ['Content-Type' => 'application/json; charset=utf-8'],
// 'content' => '{"ok":true}',
// ]
String casting
Casting the object to a string returns the current body:
<?php
$this->response->set_content('Hello World');
echo $this->response; // Hello World
$body = (string) $this->response; // 'Hello World'
Method |
Signature |
Description |
|---|---|---|
|
|
Reset status, headers, content, cookies, and sent flag |
|
|
Return a snapshot array (status code, status text, headers, content) |
|
— |
Cast the response body to a string |
Common Patterns
REST API controller
<?php
public function show($id)
{
$user = $this->user_model->find($id);
if ( ! $user)
{
$this->response->send_not_found('User not found');
}
$this->response->send_json_success($user);
}
public function store()
{
// ... validate and save ...
$this->response->send_created($user, '/users/' . $user['id']);
}
public function destroy($id)
{
$this->user_model->delete($id);
$this->response->send_no_content();
}
Returning validation errors
<?php
if ( ! $this->form_validation->run())
{
$this->response->send_json_validation(
$this->form_validation->error_array()
);
}
Adding security and CORS headers globally
<?php
$this->response
->with_security_headers()
->with_cors('https://app.example.com')
->send_json_success($data);
Caching a public resource
<?php
$this->response
->cache(86400)
->set_html_content($view)
->send();
Streaming a large CSV export
<?php
public function export()
{
$this->response->stream(function() {
$handle = fopen('php://output', 'w');
fputcsv($handle, ['id', 'name', 'email']);
foreach ($this->user_model->all() as $row)
{
fputcsv($handle, $row);
}
fclose($handle);
}, [
'Content-Type' => 'text/csv',
'Content-Disposition' => 'attachment; filename="users.csv"',
]);
}
Tips and Best Practices
Use
send_json_success()andsend_json_error()for all API endpoints to keep response envelopes consistent.Use
send_json_validation()for input validation errors — it always returns 422 with a structurederrorsfield.Use
send_created()for POST endpoints that create resources — it sets theLocationheader automatically.Use
send_no_content()for DELETE endpoints instead of sending an empty JSON object.Call
with_security_headers()in a base controller__construct()to apply security headers to all responses.Use
no_cache()on any response containing sensitive or user-specific data.Use
to_array()when logging or unit-testing responses to inspect state without triggering a real HTTP send.Always run cleanup code before
redirect()— it callsexitand nothing after it will execute.Queue cookies via
set_cookie()beforesend()— cookies cannot be set after headers are already sent.Prefer
send_event_stream()over manually configuring SSE headers and output buffering.