rfc:continue_ob

This is an old revision of the document!


PHP RFC: Continue output buffering despite aborted connection

Introduction

The output buffering technique is used to speed up output, but also to capture intermediate output and use it elsewhere.

Often, particularly with functions which directly generate output, this is the only way to accumulate that data.

Current Status

As of PHP-5.4

ignore_user_abort = FALSE

The script ends as soon as an aborted connection is detected, either by an unbuffered write or an output exceeding its chunk size (which would result in an unbuffered write).

ignore_user_abort = TRUE

The script continues to run, but any already buffered output will be discarded after processing by any output handler, and more importantly, any output generated by the script is simply discarded, without ever hitting the output buffer or any output handler. Output buffers and handlers will just sit in the stack until the output layer is deactivated.

There are a few unimportant functions already broken now:

  • phpinfo
  • highlight_{file,string} with return_output=TRUE
  • print_r, var_export with return_output=TRUE
  • SoapServer::handle (unimportant because the connection is already broken)

Proposal

Let the output buffering functions stay usable after the connection was already aborted.

This will be effective only for scripts that do set ignore_user_abort, i.e. script execution will end when an aborted connection was detected and ignore_user_abort was not set, just as it used to.

ignore_user_abort = FALSE

Nothing changes.

ignore_user_abort = TRUE

The output buffer stack stays intact and usable. Data generated by a script will be passed to any output buffers, which will call respective output handlers to process the buffer.

Only now will any generated data of the output handler be discarded. That is, before the direct unbuffered write to the SAPI.

Bacon^WBenefits

Usage of ob_start([callback]) behaves the same, whether the connection was aborted or not. Still, you have to deliberately enable it with ignore_user_abort(TRUE).

Backward Incompatible Changes

Output handlers will be called when ignore_user_abort is TRUE.

Proposed PHP Version(s)

PHP 7.0

Unaffected PHP Functionality

Standard behavior will stay the same.

Proposed Voting Choices

Simple YES/NO vote with a 50%+1 majority needed to accept this RFC.

Implementation

diff --git a/main/output.c b/main/output.c
index 22ac26a..a0a300b 100644
--- a/main/output.c
+++ b/main/output.c
@@ -242,9 +242,6 @@ PHPAPI int php_output_get_status(void)
  * Unbuffered write */
 PHPAPI size_t php_output_write_unbuffered(const char *str, size_t len)
 {
-       if (OG(flags) & PHP_OUTPUT_DISABLED) {
-               return 0;
-       }
        if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
                return sapi_module.ub_write(str, len);
        }
@@ -256,13 +253,13 @@ PHPAPI size_t php_output_write_unbuffered(const char *str, size_t len)
  * Buffered write */
 PHPAPI size_t php_output_write(const char *str, size_t len)
 {
-       if (OG(flags) & PHP_OUTPUT_DISABLED) {
-               return 0;
-       }
        if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
                php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len);
                return len;
        }
+       if (OG(flags) & PHP_OUTPUT_DISABLED) {
+               return 0;
+       }
        return php_output_direct(str, len);
 }
 /* }}} */

References

A bug about the current behavior:
https://bugs.php.net/bug.php?id=67381

A bug about apparent pre-5.4 behavior:
https://bugs.php.net/bug.php?id=64152

Changelog

  • 1.0 Proposed
  • 1.1 Rewordings, list of broken internal functions
rfc/continue_ob.1424361665.txt.gz · Last modified: 2017/09/22 13:28 (external edit)