From f43a22477804404d0bd0ec64899c2214a4e70ad5 Mon Sep 17 00:00:00 2001 From: Yoshinari Takaoka Date: Sat, 27 Jan 2024 20:22:15 +0900 Subject: [PATCH] [status working] Document details of output buffering / output control https://github.com/php/doc-en/commit/7610e990293c87168d026ad078d8272e643e2c23 --- reference/outcontrol/book.xml | 5 +- .../outcontrol/flushing-system-buffers.xml | 158 +++++ reference/outcontrol/output-buffering.xml | 117 ++++ .../outcontrol/user-level-output-buffers.xml | 634 ++++++++++++++++++ 4 files changed, 913 insertions(+), 1 deletion(-) create mode 100644 reference/outcontrol/flushing-system-buffers.xml create mode 100644 reference/outcontrol/output-buffering.xml create mode 100644 reference/outcontrol/user-level-output-buffers.xml diff --git a/reference/outcontrol/book.xml b/reference/outcontrol/book.xml index 37513c49c10..bc5ee7911ce 100644 --- a/reference/outcontrol/book.xml +++ b/reference/outcontrol/book.xml @@ -1,6 +1,6 @@ - + @@ -23,6 +23,9 @@ &reference.outcontrol.setup; &reference.outcontrol.constants; + &reference.outcontrol.output-buffering; + &reference.outcontrol.flushing-system-buffers; + &reference.outcontrol.user-level-output-buffers; &reference.outcontrol.examples; &reference.outcontrol.reference; diff --git a/reference/outcontrol/flushing-system-buffers.xml b/reference/outcontrol/flushing-system-buffers.xml new file mode 100644 index 00000000000..ff8116e083e --- /dev/null +++ b/reference/outcontrol/flushing-system-buffers.xml @@ -0,0 +1,158 @@ + + + + +
+ Flushing System Buffers + + PHP provides two related ways + to flush (send and discard the contents of) system buffers: + through calling flush + and through enabling implicit flushing + with ob_implicit_flush + or the implicit_flush + &php.ini; setting. + + + With implicit flushing disabled, PHP will flush output only + when flush is called or when the script ends. + + + With implicit flushing enabled, PHP will attempt to flush + after every block of code resulting in output. + Output in this context is non-zero length data that is: + + + + outside of the <?php ?> tags + + + + + printed by language constructs and functions + whose explicit purpose is to output user provided variables or strings such as + echo, print, + printf, var_dump, + var_export, vprintf + + + + + printed by functions whose purpose is to collect and output + data/information on the running script or PHP such as + debug_print_backtrace, phpcredits, + phpinfo, + ReflectionExtension::info + + + + + printed by PHP on an uncaught exception or an unhandled error + (subject to the settings of + display_errors + and error_reporting) + + + + + anything written to php://output + + + + + + + Printing empty strings or sending headers is not considered output + and will not result in a flush operation. + + + + + If implicit flushing is enabled, control characters + (e.g. "\n", "\r", + "\0") + will trigger flushing as well. + + +
+ +
+ Limitations + + This functionality cannot flush user-level output buffers. + To use these together, user-level output buffers must be flushed + before flushing system buffers in order for PHP to produce any output. + + + + Calling flush or implicit flushing being enabled + can interfere with output handlers of user-level output buffers + that set and send headers in a web context + (e.g. ob_gzhandler) + by sending headers before these handlers can do so. + + + + Buffering implemented by the underlying software/hardware + cannot be overridden by PHP and should be taken into account + when working with PHP's buffer control functions. + Checking the web servers/browsers/consoles buffering settings + and working with these can alleviate possible issues. + Working in a web context, either the web server's buffering settings + or the script's buffering could be adjusted to work in tandem + whereas working around the buffering strategies of various browsers + can be achieved by adjusting buffering in the PHP script. + On consoles that implement line buffering, + newline characters could be inserted in the appropriate places + before flushing output. + +
+ +
+ <acronym>SAPI</acronym> Differences In Flushing + + Although flushing is implemented by each SAPI + in a slightly different way, + these implementations fall in one of two categories: + + + + SAPIs used in a web context will flush headers first + followed by the output. + Apache2Handler, CGI, + FastCGI and FPM + are such SAPIs + + + + + other SAPIs + such as CLI and embed + will flush output only + + + + +
+ +
+ diff --git a/reference/outcontrol/output-buffering.xml b/reference/outcontrol/output-buffering.xml new file mode 100644 index 00000000000..d8800ae239a --- /dev/null +++ b/reference/outcontrol/output-buffering.xml @@ -0,0 +1,117 @@ + + + + +
+ Output Buffering + + Output buffering is the buffering (temporary storage) of output + before it is flushed (sent and discarded) to the browser (in a web context) + or to the shell (on the command line). + While output buffering is active no output is sent from the script, + instead the output is stored in an internal buffer. + +
+ +
+ Buffering Affecting PHP + + PHP relies on the underlying software/hardware infrastructure + when flushing output. + Buffering implemented by consoles on the command line (e.g. line buffered) + or web servers and browser in a web context (e.g. fully buffered) + do affect when output is displayed to the end-user. + Some of these effects can be eliminated by fine-tuning server settings + and/or aligning buffer sizes of the various layers. + +
+ +
+ Output Buffering Control In PHP + + PHP provides a fully buffered user-level output buffer + with functions to start, manipulate and turn off the buffer + (most ob_* functions), + and two functions to flush the underlying system buffers + (flush and ob_implicit_flush). + Some of this functionality can be set and/or configured + using the appropriate &php.ini; settings as well. + +
+ +
+ Use Cases + + Output buffering is generally useful in situations when the buffered output + is modified or inspected, or it is used more than once in a request; + or when the controlled flushing of output is desired. + Specific use cases include: + + + + caching the result of compute/time intensive scripts + for example by generating static HTML pages + + + + + re-using the generated output by displaying it, saving it to a file + and/or sending it by email + + + + + flushing the head of an HTML page + separate from the body allows browsers + to load external resources while the script executes + potentially more time consuming processes + (e.g. database/file access, external network connection). + This is only useful if the HTTP status code + cannot change after the headers are sent + + + + + extracting information from functions that would otherwise produce output + (e.g. phpinfo) + + + + + controlling the output of third-party code by modifying/using parts + (e.g. extracting data, replacing words/phrases, + adding missing HTML tags), + or discarding it entirely under certain conditions (e.g. errors) + + + + + polyfilling certain unavailable web server functionality + (e.g. compressing or encoding output) + + + + +
+ +
+ diff --git a/reference/outcontrol/user-level-output-buffers.xml b/reference/outcontrol/user-level-output-buffers.xml new file mode 100644 index 00000000000..7c40f53d6b0 --- /dev/null +++ b/reference/outcontrol/user-level-output-buffers.xml @@ -0,0 +1,634 @@ + + + + +
+ User-Level Output Buffers + + User-level output buffers can be started, manipulated + and terminated from PHP code. + Each of these buffers includes an output buffer + and an associated output handler function. + +
+ +
+ What Output Is Buffered? + + PHP's user-level output buffers buffer all output after they are started + until they are turned off or the script ends. + Output in the context of PHP's user-level output buffer + is everything that PHP would display or send back to the browser. + In practical terms, output is non-zero length data that is: + + + + + + + Data that is written directly to stdout + or passed to an SAPI function with a similar functionality + will not be captured by user-level output buffers. + This includes + writing data to stdout with fwrite + or sending headers using header + or setcookie. + + +
+ +
+ Turning Output Buffering On + + Output buffering can be turned on by using + the ob_start function or by setting + the output_buffering + and output_handler + &php.ini; settings. + While both can create output buffers, + ob_start is more flexible + as it accepts user-defined functions as output handlers + and the operations allowed on the buffer (flush, clean, remove) + can be set as well. + Buffers started with ob_start will be active + from the line the function was called, + while those started with + output_buffering + will be buffering output from the first line of the script. + + + PHP is also shipped with a built-in "URL-Rewriter" + output handler which starts its own output buffer and only allows + up to two instances of it running at any time + (one for user-level URL-rewriting + and one for transparent session id support). + These buffers can be started by calling + the output_add_rewrite_var function + and/or by enabling the + session.use_trans_sid + &php.ini; setting. + + + The bundled zlib extension has its own + output buffer which can be enabled by using the + zlib.output_compression + &php.ini; setting. + + + + While "URL-Rewriter" is special + in that it only allows up to two instances of it running at any one time, + all user-level output buffers use the same underlying buffers + used by ob_start + with their functionality implemented by a custom output handler function. + As such, all of their functionality can be emulated by userland code. + + +
+ +
+ Nesting Output Buffers + + If there is an output buffer active when a new buffer is started, + the new buffer will be nested inside the previously active buffer. + The inner buffer will behave the same way regardless whether it is nested + but output buffered by it will not be buffered by the outer buffer. + Only output flushed by the inner buffer will be buffered by the outer buffer. + + + Most ob_* functions only work + with the active output buffer (the last one started) + therefore only the active buffer can be flushed, cleaned and turned off. + The functions that work with other buffers are + ob_list_handlers + which returns the list of all output handlers in use + and ob_get_status + which can return information on the active buffer only + or on all buffers in use. + + + Calling ob_get_level + or ob_get_status will return + the nesting level of the active output buffer. + + + + The value for identical levels between ob_get_level + and ob_get_status is off by one. + For ob_get_level + the first level is 1, + whereas for ob_get_status + the first level is 0. + + +
+ +
+ Buffer Size + + Buffer sizes are expressed by integers + and represent the number of bytes the buffer can store without flushing. + When the size of output in the buffer exceeds the size of the buffer, + the contents of the buffer are sent to the output handler, + its return value is flushed and the buffer is cleared. + + + With the exception of "URL-Rewriter", + the size of output buffers can be set when the buffer is started. + If set to 0, + the output buffer is only limited by the memory available to PHP. + If set to 1, + the buffer is flushed after every block of code producing + any non-zero length output. + + + The size of output buffers can be retrieved by calling + ob_get_status. + + + Output buffers started with ob_start + will have their buffer sizes set to the integer value passed to + the function's second chunk_size parameter. + If omitted, it is set to 0. + + + The output buffer started with + output_buffering + set to "On" will have its buffer size set to 0. + If set to an integer than buffer size will correspond to that number. + + + "URL-Rewriter"'s buffer size is set to 0, + therefore it is only limited by the memory available to PHP. + + + The size of zlib's output buffer is controlled by the + zlib.output_compression + &php.ini; setting. + If set to "On" the buffer size will be + "16K"/16384. + If set to an integer then buffer size will correspond to that number in bytes. + +
+ +
+ Operations Allowed On Buffers + + The operations allowed on buffers can be controlled + by passing one of the + buffer control flags + to ob_start's third + flags parameter. + If omitted, all operations are allowed by default. + If 0 is used instead, + the buffer cannot be flushed, cleaned or removed + but it's contents can still be retrieved. + + + PHP_OUTPUT_HANDLER_CLEANABLE allows + ob_clean to clean the contents of the buffer. + + + + The absence of the PHP_OUTPUT_HANDLER_CLEANABLE flag + will not prevent ob_end_clean + or ob_get_clean from clearing the contents of the buffer. + + + + PHP_OUTPUT_HANDLER_FLUSHABLE allows + ob_flush to flush the contents of the buffer. + + + + The absence of the PHP_OUTPUT_HANDLER_FLUSHABLE flag + will not prevent ob_end_flush + or ob_get_flush from flushing the contents of the buffer. + + + + PHP_OUTPUT_HANDLER_REMOVABLE allows + ob_end_clean, ob_end_flush, + ob_get_clean or ob_get_flush + to turn off the buffer. + + + PHP_OUTPUT_HANDLER_STDFLAGS, + the combination of the three flags will allow each of the three operations + to be performed on the buffer. + +
+ +
+ Flushing, Accessing And Cleaning Buffer Contents + + Flushing sends and discards the contents of the active buffer. + Output buffers get flushed when the size of the output + exceeds the size of the buffer; the script ends or + ob_flush, ob_end_flush + or ob_get_flush is called. + + + + Calling ob_end_flush + or ob_get_flush will turn off the active buffer. + + + + + Flushing buffers will flush the return value of the output handler + which can differ from the contents of the buffer. + For example, using ob_gzhandler will compress + the output and flush the compressed output. + + + + The contents of the active buffer can be retrieved by calling + ob_get_contents, ob_get_clean + or ob_get_flush. + + + If only the length of the buffer's contents are needed, + ob_get_length or ob_get_status + will return the length of the contents in bytes. + + + + Calling ob_get_clean + or ob_get_flush will turn off the active buffer + after returning the its contents. + + + + The contents of the active buffer can be cleaned by calling + ob_clean, ob_end_clean + or ob_get_clean. + + + + Calling ob_end_clean + or ob_get_clean will turn off the active buffer. + + +
+ +
+ Turning Buffers Off + + Output buffers can be turned off by calling + ob_end_clean, ob_end_flush, + ob_get_flush or ob_get_clean. + + + + Output buffers started without the + PHP_OUTPUT_HANDLER_REMOVABLE flag + cannot be turned off and may generate an E_NOTICE. + + + + Every output buffer that has not been closed by the end of the script + or when exit is called will be flushed + and turned off by PHP's shutdown process. + The buffers will be flushed and turned off in reverse order + of their starting up. + The last buffered started will be first, + the first buffer started will be last to be flushed and turned off. + + + + If flushing of the buffer's contents is not desired, + a custom output handler should be used to prevent flushing during shutdown. + + +
+ +
+ Output Handlers + + Output handlers are callables associated with output buffers + that are invoked by calling ob_clean, + ob_flush, ob_end_flush, + ob_get_flush, ob_end_clean, + ob_get_clean or during PHP's shutdown process. + + + + The shutdown process will flush the return value of the handler. + + + + If omitted or &null; when starting the output buffer + the internal "default output handler" will be used + which returns the unmodified contents of the buffer when invoked. + Output handlers can be used to return a modified version + of the buffer's contents and/or have side-effects (e.g. send headers). + + + PHP comes with two internal output handlers: + "default output handler" + and "URL-Rewriter" (which is integrated into + its own output buffer and only up to two instances of it can be started). + + + The bundled extensions include four additional output handlers: + mb_output_handler, ob_gzhandler, + ob_iconv_handler, ob_tidyhandler. + +
+ +
+ Working With Output Handlers + + When invoked, output handlers are passed the contents of the buffer + and a bitmask indicating the status of output buffering. + + + + string + + handler + + + string + buffer + + + int + phase + + + + + buffer + + + Contents of the output buffer. + + + + + phase + + + Bitmask of + + PHP_OUTPUT_HANDLER_* + constants + . + + + + + + + + Calling any of the following functions from within an output handler + will result in a fatal error: + ob_clean, ob_end_clean, + ob_end_flush, ob_flush, + ob_get_clean, ob_get_flush, + ob_start. + + + + + If the PHP_OUTPUT_HANDLER_DISABLED of a handler is set, + the handler will not be invoked by calling + ob_end_clean, ob_end_flush, + ob_get_clean, ob_get_flush + or during PHP's shutdown process. + This flag has no effect on when calling ob_clean + or ob_flush. + + + + + The working directory of the script can change inside the shutdown function + under some web servers, e.g. Apache or the built-in web server. + + +
+ +
+ Flags Passed To Output Handlers + + The bitmask passed to the second phase parameter + of the output handler provides information on the invocation of the handler. + + + + The bitmask can include more than one flag + and the bitwise & operator should be used + to check whether a flag is set. + + + + + The value of PHP_OUTPUT_HANDLER_WRITE and its alias + PHP_OUTPUT_HANDLER_CONT is 0 + therefore whether it is set can only be determined + by using an + equality operator + (== or ===). + + + + The following flags are set in a specific phase of the handler's lifecycle: + PHP_OUTPUT_HANDLER_START is set + when a handler is invoked for the first time. + PHP_OUTPUT_HANDLER_FINAL + or its alias PHP_OUTPUT_HANDLER_END + is set when a handler is invoked for the last time, + i.e. it is being turned off. This flag is also set + when buffers are being turned off by PHP's shutdown process. + + + The following flags are set by a specific invocation of the handler: + PHP_OUTPUT_HANDLER_FLUSH is set + when the handler is invoked by calling ob_flush. + PHP_OUTPUT_HANDLER_WRITE + or its alias PHP_OUTPUT_HANDLER_CONT + is set when the size of its contents equals or exceeds the size of the buffer + and the handler is invoked while the buffer is being automatically flushed. + PHP_OUTPUT_HANDLER_FLUSH is set + when the handler is invoked by calling ob_clean, + ob_end_clean or ob_get_clean. + When ob_end_clean or ob_get_clean + is called, PHP_OUTPUT_HANDLER_FINAL is set as well. + + + + When ob_end_flush or ob_get_flush + is called, PHP_OUTPUT_HANDLER_FINAL is set + but PHP_OUTPUT_HANDLER_FLUSH is not. + + +
+ +
+ Output Handler Return Values + + The return value of the output handler is internally coerced into a string + following standard PHP type semantics, with two exceptions: + arrays and booleans. + + + Arrays are converted into the string "Array" + but the Array to string conversion warning + is not triggered. + + + If the handler returns &false; the contents of the buffer are returned. + If the handler returns &true; an empty string is returned. + + + + If a handler returns &false; or throws an exception + its PHP_OUTPUT_HANDLER_DISABLED status flag is set. + + +
+ +
+ Exceptions Thrown In Output Handlers + + If an uncaught exception is thrown in an output handler + the program terminates and the handler is invoked + by the shutdown process after which + the "Uncaught Exception" error message is flushed. + + + If the uncaught exception is thrown in a handler + invoked by ob_flush, + ob_end_flush or ob_get_flush, + the contents of the buffer are flushed before the error message. + + + If an uncaught exception is thrown in an output handler during shutdown, + the handler is terminated and neither the contents of the buffer + nor the error message is flushed. + + + + If a handler throws an exception + its PHP_OUTPUT_HANDLER_DISABLED status flag is set. + + +
+ +
+ Errors Raised In Output Handlers + + If a non-fatal error is raised in an output handler + the program continues execution. + + + If the non-fatal error is raised in a handler invoked by + ob_flush, ob_end_flush + or ob_get_flush, + the buffer flushes certain data depending on the return value of the handler. + If the handler returns &false; the buffer and the error message are flushed. + If the returns anything else the handler return value is flushed + but not the error message. + + + + If a handler returns &false; + its PHP_OUTPUT_HANDLER_DISABLED status flag is set. + + + + If a fatal error is raised in an output handler + the program terminates and the handler is invoked + by the shutdown process after which the error message is flushed. + + + If the fatal error is raised in a handler + invoked by ob_flush, + ob_end_flush or ob_get_flush, + the contents of the buffers are flushed before the error message. + + + If a fatal error is raised in an output handler during shutdown + the program terminates without flushing the buffer or the error message. + +
+ +
+ Output In Output Handlers + + In specific circumstances, output produced in the handler is flushed + along with the contents of the buffer. + This output is not appended to the buffer and is not part of the string + returned by ob_get_flush. + + + During flush operations (calling ob_flush, + ob_end_flush, ob_get_flush + and during shutdown) + if the return value of a handler is &false; + the contents of the buffer are flushed followed by the output. + If the handler is not invoked during shutdown + the handler throwing an exception or exit being called + results in the same behavior. + + + + If a handler returns &false; + its PHP_OUTPUT_HANDLER_DISABLED status flag is set. + + +
+ +
+ Output Handler Status Flags + + The + + handler status flags + of the buffer's flags bitmask + are set every time to the output handler is invoked + and are part of the flags returned by + ob_get_status. + If the handler successfully executes and does not return &false;, + PHP_OUTPUT_HANDLER_STARTED and + PHP_OUTPUT_HANDLER_PROCESSED is set. + If the handler returns &false; or throws an exception while executing, + PHP_OUTPUT_HANDLER_STARTED and + PHP_OUTPUT_HANDLER_DISABLED is set. + + + + If the PHP_OUTPUT_HANDLER_DISABLED of a handler is set, + the handler will not be invoked by calling + ob_end_clean, ob_end_flush, + ob_get_clean, ob_get_flush + or during PHP's shutdown process. + This flag has no effect on when calling ob_clean + or ob_flush. + + +
+ +
+