Skip to content

v5 - Fix process state in long-lived runtimes - #3469

Merged
odan merged 1 commit into
slimphp:5.xfrom
odan:v5-workers
Aug 26, 2026
Merged

v5 - Fix process state in long-lived runtimes#3469
odan merged 1 commit into
slimphp:5.xfrom
odan:v5-workers

Conversation

@odan

@odan odan commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Small correctness fixes for leftover process state and empty JSON error bodies. These show up hardest under persistent workers (FrankenPHP, RoadRunner, Swoole) because the PHP process is reused.

Slim 5 already avoids storing the last request on App. This PR only fixes real leftover-state bugs and one encoding hole. It does not lock routes, close response streams, or change logging.

Fixed

Output buffering leaks across requests

OutputBufferingMiddleware used ob_get_clean() / ob_end_clean(), which pop only the innermost buffer.

If a view, PDF lib, or echo path started a nested buffer and did not close it (or threw), Slim popped the nested one and left its own buffer installed. In a worker that buffer — and any string still in it — lived until the process was killed.

It now records ob_get_level() and pops back to that level on both success and exception.

Error handler left installed after the first request

ErrorExceptionMiddleware only called restore_error_handler() when set_error_handler() returned a previous handler.

On the first request that value is null, so restore was skipped. Slim’s “turn PHP errors into ErrorException” handler stayed installed for the rest of the process, including between requests.

It now always restores.

Empty JSON error body on invalid UTF-8

json_encode() returns false when any string contains invalid UTF-8. An exception message with raw bytes (common when user input is echoed into the exception) produced a zero-length body with Content-Type: application/json. Clients then failed to parse the error.

JSON_PARTIAL_OUTPUT_ON_ERROR does not cover JSON_ERROR_UTF8. Added JSON_INVALID_UTF8_SUBSTITUTE so invalid sequences become U+FFFD and the payload stays valid JSON.

Same fix as #3465 on 4.x (JsonErrorRenderer); v5’s equivalent is JsonExceptionMiddleware.

Changed (breaking)

Route arguments no longer live on Route

Removed RouteInterface::getArgument(), getArguments(), and setArguments().

Slim 5 already puts match args on a per-request RouteMatch. The Route instance is the FastRoute handler and lives for the process lifetime. setArguments() wrote request-shaped data onto that shared object, so one request’s args could be read on the next. The framework never called these methods.

Get args from:

  • the handler $args array
  • $request->getAttribute(RouteMatch::class)
  • request attributes via RoutingArgumentsMiddleware

@odan odan added the Slim 5 label Aug 26, 2026
@odan
odan merged commit 79548b1 into slimphp:5.x Aug 26, 2026
@akrabat akrabat assigned akrabat and unassigned akrabat Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants