Filtering the PSR-7 body in middleware
Sometimes, there’s a requirement to alter the data in the Response’s body after it has been created by your controller action. For example, we may want to ensure that our brand name is consistently capitalised.
One way to do this is to create middleware that looks like this:
$brandFilter = function ($request, $response, $next) { // call next middleware $response = $next($request, $response); $content = (string)$response->getBody(); $newContent = str_ireplace('nineteen feet', 'Nineteen Feet', $content); $response->getBody()->rewind(); $response->getBody()->write($newContent); return $response; };
This works perfectly, so if my response body contains “I consult through my company, nineteen feet.“, then the output of the $brandFilter middleware is “I consult through thought my company, Nineteen Feet.“, which is exactly what we want.
That’s great, but what happens if the new string is shorter than the old one? For instance, suppose I want to replace all uses of “nineteen feet” with “19FT”.
Using the same middleware, but changing the str_ireplace call with:
$newContent = str_ireplace('nineteen feet', '19FT', $content);
creates this output:
I consult through my company, 19FT.een feet.
That’s not quite what we wanted! This result is because the new string is shorter, so the characters from the old string are still in the PHP stream and as we haven’t change the length, they are still there. The PSR-7 StreamInterface doesn’t allow us access to the underlying stream, so we can’t call ftruncate on it.
Hence, the easiest solution is to replace the Response’s PSR-7 StreamInterface object with a new one containing what we need:
$brandFilter = function ($request, $response, $next) { // call next middleware $response = $next($request, $response); $content = (string)$response->getBody(); $newContent = str_ireplace('nineteen feet', '19FT', $content); $newBody = new \Slim\Http\Body(fopen('php://temp', 'r+')); $newBody->write($newContent); return $response->withBody($newBody); };
The output is now what we expect:
I consult through my company, 19FT.
The buzzword middleware is used wrong by the slim framework, it should be called interceptor:
https://en.wikipedia.org/wiki/Interceptor_pattern
Arguably it's more an implementation of the Pipeline Processing pattern. The term HTTP middleware to describe this dates back to Rack and is used in every language that talks HTTP.
I really didn't get that your last example.
https://3v4l.org/u6egS
As you can see, the result is "I consult through my company, 19FT."
what made you think that result?
A PSR-7 Response body is a Stream, not a simple string.