Skip to content

Commit d92c65f

Browse files
authored
Merge pull request #571 from flightphp/response-body-callback
Added ability to convert the response body with callbacks
2 parents 4d79dea + 9be596f commit d92c65f

8 files changed

Lines changed: 110 additions & 36 deletions

File tree

flight/Engine.php

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ public function after(string $name, callable $callback): void
314314
*/
315315
public function get(?string $key = null)
316316
{
317-
if (null === $key) {
317+
if ($key === null) {
318318
return $this->vars;
319319
}
320320

@@ -360,7 +360,7 @@ public function has(string $key): bool
360360
*/
361361
public function clear(?string $key = null): void
362362
{
363-
if (null === $key) {
363+
if ($key === null) {
364364
$this->vars = [];
365365
return;
366366
}
@@ -570,9 +570,11 @@ public function _start(): void
570570
public function _error(Throwable $e): void
571571
{
572572
$msg = sprintf(
573-
'<h1>500 Internal Server Error</h1>' .
574-
'<h3>%s (%s)</h3>' .
575-
'<pre>%s</pre>',
573+
<<<HTML
574+
<h1>500 Internal Server Error</h1>
575+
<h3>%s (%s)</h3>
576+
<pre>%s</pre>
577+
HTML,
576578
$e->getMessage(),
577579
$e->getCode(),
578580
$e->getTraceAsString()
@@ -603,8 +605,8 @@ public function _stop(?int $code = null): void
603605
{
604606
$response = $this->response();
605607

606-
if (!$response->sent()) {
607-
if (null !== $code) {
608+
if ($response->sent() === false) {
609+
if ($code !== null) {
608610
$response->status($code);
609611
}
610612

@@ -729,12 +731,12 @@ public function _redirect(string $url, int $code = 303): void
729731
{
730732
$base = $this->get('flight.base_url');
731733

732-
if (null === $base) {
734+
if ($base === null) {
733735
$base = $this->request()->base;
734736
}
735737

736738
// Append base url to redirect url
737-
if ('/' !== $base && false === strpos($url, '://')) {
739+
if ($base !== '/' && strpos($url, '://') === false) {
738740
$url = $base . preg_replace('#/+#', '/', '/' . $url);
739741
}
740742

@@ -756,7 +758,7 @@ public function _redirect(string $url, int $code = 303): void
756758
*/
757759
public function _render(string $file, ?array $data = null, ?string $key = null): void
758760
{
759-
if (null !== $key) {
761+
if ($key !== null) {
760762
$this->view()->set($key, $this->view()->fetch($file, $data));
761763
return;
762764
}
@@ -833,7 +835,7 @@ public function _jsonp(
833835
*/
834836
public function _etag(string $id, string $type = 'strong'): void
835837
{
836-
$id = (('weak' === $type) ? 'W/' : '') . $id;
838+
$id = (($type === 'weak') ? 'W/' : '') . $id;
837839

838840
$this->response()->header('ETag', '"' . str_replace('"', '\"', $id) . '"');
839841

flight/net/Request.php

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public function __construct(array $config = [])
151151
'method' => self::getMethod(),
152152
'referrer' => self::getVar('HTTP_REFERER'),
153153
'ip' => self::getVar('REMOTE_ADDR'),
154-
'ajax' => 'XMLHttpRequest' === self::getVar('HTTP_X_REQUESTED_WITH'),
154+
'ajax' => self::getVar('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest',
155155
'scheme' => self::getScheme(),
156156
'user_agent' => self::getVar('HTTP_USER_AGENT'),
157157
'type' => self::getVar('CONTENT_TYPE'),
@@ -160,7 +160,7 @@ public function __construct(array $config = [])
160160
'data' => new Collection($_POST),
161161
'cookies' => new Collection($_COOKIE),
162162
'files' => new Collection($_FILES),
163-
'secure' => 'https' === self::getScheme(),
163+
'secure' => self::getScheme() === 'https',
164164
'accept' => self::getVar('HTTP_ACCEPT'),
165165
'proxy_ip' => self::getProxyIpAddress(),
166166
'host' => self::getVar('HTTP_HOST'),
@@ -188,12 +188,12 @@ public function init(array $properties = []): self
188188
// This rewrites the url in case the public url and base directories match
189189
// (such as installing on a subdirectory in a web server)
190190
// @see testInitUrlSameAsBaseDirectory
191-
if ('/' !== $this->base && '' !== $this->base && 0 === strpos($this->url, $this->base)) {
191+
if ($this->base !== '/' && $this->base !== '' && strpos($this->url, $this->base) === 0) {
192192
$this->url = substr($this->url, \strlen($this->base));
193193
}
194194

195195
// Default url
196-
if (empty($this->url)) {
196+
if (empty($this->url) === true) {
197197
$this->url = '/';
198198
} else {
199199
// Merge URL query parameters with $_GET
@@ -203,11 +203,11 @@ public function init(array $properties = []): self
203203
}
204204

205205
// Check for JSON input
206-
if (0 === strpos($this->type, 'application/json')) {
206+
if (strpos($this->type, 'application/json') === 0) {
207207
$body = $this->getBody();
208-
if ('' !== $body) {
208+
if ($body !== '') {
209209
$data = json_decode($body, true);
210-
if (is_array($data)) {
210+
if (is_array($data) === true) {
211211
$this->data->setData($data);
212212
}
213213
}
@@ -225,13 +225,13 @@ public function getBody(): string
225225
{
226226
$body = $this->body;
227227

228-
if ('' !== $body) {
228+
if ($body !== '') {
229229
return $body;
230230
}
231231

232232
$method = $this->method ?? self::getMethod();
233233

234-
if ('POST' === $method || 'PUT' === $method || 'DELETE' === $method || 'PATCH' === $method) {
234+
if ($method === 'POST' || $method === 'PUT' || $method === 'DELETE' || $method === 'PATCH') {
235235
$body = file_get_contents($this->stream_path);
236236
}
237237

@@ -247,9 +247,9 @@ public static function getMethod(): string
247247
{
248248
$method = self::getVar('REQUEST_METHOD', 'GET');
249249

250-
if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
250+
if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']) === true) {
251251
$method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
252-
} elseif (isset($_REQUEST['_method'])) {
252+
} elseif (isset($_REQUEST['_method']) === true) {
253253
$method = $_REQUEST['_method'];
254254
}
255255

@@ -275,9 +275,9 @@ public static function getProxyIpAddress(): string
275275
$flags = \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE;
276276

277277
foreach ($forwarded as $key) {
278-
if (\array_key_exists($key, $_SERVER)) {
278+
if (\array_key_exists($key, $_SERVER) === true) {
279279
sscanf($_SERVER[$key], '%[^,]', $ip);
280-
if (false !== filter_var($ip, \FILTER_VALIDATE_IP, $flags)) {
280+
if (filter_var($ip, \FILTER_VALIDATE_IP, $flags) !== false) {
281281
return $ip;
282282
}
283283
}
@@ -322,7 +322,7 @@ public static function getHeaders(): array
322322
{
323323
$headers = [];
324324
foreach ($_SERVER as $key => $value) {
325-
if (0 === strpos($key, 'HTTP_')) {
325+
if (strpos($key, 'HTTP_') === 0) {
326326
// converts headers like HTTP_CUSTOM_HEADER to Custom-Header
327327
$key = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
328328
$headers[$key] = $value;
@@ -386,7 +386,7 @@ public static function parseQuery(string $url): array
386386
$params = [];
387387

388388
$args = parse_url($url);
389-
if (isset($args['query'])) {
389+
if (isset($args['query']) === true) {
390390
parse_str($args['query'], $params);
391391
}
392392

@@ -401,13 +401,13 @@ public static function parseQuery(string $url): array
401401
public static function getScheme(): string
402402
{
403403
if (
404-
(isset($_SERVER['HTTPS']) && 'on' === strtolower($_SERVER['HTTPS']))
404+
(isset($_SERVER['HTTPS']) === true && strtolower($_SERVER['HTTPS']) === 'on')
405405
||
406-
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'])
406+
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) === true && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
407407
||
408-
(isset($_SERVER['HTTP_FRONT_END_HTTPS']) && 'on' === $_SERVER['HTTP_FRONT_END_HTTPS'])
408+
(isset($_SERVER['HTTP_FRONT_END_HTTPS']) === true && $_SERVER['HTTP_FRONT_END_HTTPS'] === 'on')
409409
||
410-
(isset($_SERVER['REQUEST_SCHEME']) && 'https' === $_SERVER['REQUEST_SCHEME'])
410+
(isset($_SERVER['REQUEST_SCHEME']) === true && $_SERVER['REQUEST_SCHEME'] === 'https')
411411
) {
412412
return 'https';
413413
}

flight/net/Response.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ class Response
128128
*/
129129
protected bool $sent = false;
130130

131+
/**
132+
* These are callbacks that can process the response body before it's sent
133+
*
134+
* @var array<int, callable> $responseBodyCallbacks
135+
*/
136+
protected array $responseBodyCallbacks = [];
137+
131138
/**
132139
* Sets the HTTP status of the response.
133140
*
@@ -429,8 +436,38 @@ public function send(): void
429436
$this->sendHeaders(); // @codeCoverageIgnore
430437
}
431438

439+
// Only for the v3 output buffering.
440+
if ($this->v2_output_buffering === false) {
441+
$this->processResponseCallbacks();
442+
}
443+
432444
echo $this->body;
433445

434446
$this->sent = true;
435447
}
448+
449+
/**
450+
* Adds a callback to process the response body before it's sent. These are processed in the order
451+
* they are added
452+
*
453+
* @param callable $callback The callback to process the response body
454+
*
455+
* @return void
456+
*/
457+
public function addResponseBodyCallback(callable $callback): void
458+
{
459+
$this->responseBodyCallbacks[] = $callback;
460+
}
461+
462+
/**
463+
* Cycles through the response body callbacks and processes them in order
464+
*
465+
* @return void
466+
*/
467+
protected function processResponseCallbacks(): void
468+
{
469+
foreach ($this->responseBodyCallbacks as $callback) {
470+
$this->body = $callback($this->body);
471+
}
472+
}
436473
}

flight/net/Router.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public function map(string $pattern, $callback, bool $pass_route = false, string
101101

102102
$methods = ['*'];
103103

104-
if (false !== strpos($url, ' ')) {
104+
if (strpos($url, ' ') !== false) {
105105
[$method, $url] = explode(' ', $url, 2);
106106
$url = trim($url);
107107
$methods = explode('|', $method);

phpstan.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ parameters:
66
level: 6
77
excludePaths:
88
- vendor
9+
- flight/util/ReturnTypeWillChange.php
910
paths:
1011
- flight
1112
- index.php

tests/EngineTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,7 @@ public function testHandleErrorWithException()
8787
public function testHandleException()
8888
{
8989
$engine = new Engine();
90-
$regex_message = preg_quote('<h1>500 Internal Server Error</h1><h3>thrown exception message (20)</h3>');
91-
$this->expectOutputRegex('~' . $regex_message . '~');
90+
$this->expectOutputRegex('~\<h1\>500 Internal Server Error\</h1\>[\s\S]*\<h3\>thrown exception message \(20\)\</h3\>~');
9291
$engine->handleException(new Exception('thrown exception message', 20));
9392
}
9493

tests/ResponseTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,37 @@ public function testOverwriteBody()
255255
$response->write('new', true);
256256
$this->assertEquals('new', $response->getBody());
257257
}
258+
259+
public function testResponseBodyCallback()
260+
{
261+
$response = new Response();
262+
$response->write('test');
263+
$str_rot13 = function ($body) {
264+
return str_rot13($body);
265+
};
266+
$response->addResponseBodyCallback($str_rot13);
267+
ob_start();
268+
$response->send();
269+
$rot13_body = ob_get_clean();
270+
$this->assertEquals('grfg', $rot13_body);
271+
}
272+
273+
public function testResponseBodyCallbackMultiple()
274+
{
275+
$response = new Response();
276+
$response->write('test');
277+
$str_rot13 = function ($body) {
278+
return str_rot13($body);
279+
};
280+
$str_replace = function ($body) {
281+
return str_replace('g', 'G', $body);
282+
};
283+
$response->addResponseBodyCallback($str_rot13);
284+
$response->addResponseBodyCallback($str_replace);
285+
$response->addResponseBodyCallback($str_rot13);
286+
ob_start();
287+
$response->send();
288+
$rot13_body = ob_get_clean();
289+
$this->assertEquals('TesT', $rot13_body);
290+
}
258291
}

tests/server/index.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,11 @@
161161

162162
Flight::map('error', function (Throwable $e) {
163163
echo sprintf(
164-
'<h1>500 Internal Server Error</h1>' .
165-
'<h3>%s (%s)</h3>' .
166-
'<pre style="border: 2px solid red; padding: 21px; background: lightgray; font-weight: bold;">%s</pre>',
164+
<<<HTML
165+
<h1>500 Internal Server Error</h1>
166+
<h3>%s (%s)</h3>
167+
<pre style="border: 2px solid red; padding: 21px; background: lightgray; font-weight: bold;">%s</pre>
168+
HTML,
167169
$e->getMessage(),
168170
$e->getCode(),
169171
str_replace(getenv('PWD'), '***CONFIDENTIAL***', $e->getTraceAsString())

0 commit comments

Comments
 (0)