I am using output buffering to process stuff (very descriptive, I know).
What I'd like to do is cause output buffering to end, have the handler functions perform their processing, and then get the resulting output as a string, not output to the browser.
Is this possible? I can't seem to work out what combination of ob_end/ob_get functions I would need to achieve this... and my initial thought of "I can just buffer the output of ob_end_flush" is... well, absurd :p
As a basic example of what I'm trying to achieve:
<?php
ob_start(function($c) {return "PASS\n";});
echo "FAIL\n";
$c = ob_get_contents();
ob_end_flush(); // outputs PASS, as it has been processed
echo $c; // outputs FAIL, because that was the content of the buffer... unprocessed...
// I want it processed.
I see the issue now with the edits and comments. You are correct that you'll need another output buffer since the callback is only called when flush or end is called and before any get in the function:
ob_start(function($c) {return "PASS\n";});
echo "FAIL\n";
ob_start();
ob_end_flush(); // buffers PASS, as it has been processed
$c = ob_get_contents();
echo $c; // outputs PASS
Related
I'm using PHPUnit to test a function which downloads a file. I want to test that the correct file is downloaded and so my idea was to check the output of the function. I'm trying to use output buffering:
ob_start();
$viewer->downloadById($fileId);
$output = ob_get_flush();
$this->assertEquals($expectedFileContents,$output);
The test passes/fails when it should, which is good. My issue is that the contents of the output buffer is also printed to the console. How do I hide this?
Use ob_get_clean() instead of ob_get_flush(). The former will remove the buffer without printing it and return its contents. The latter will do the same and print the contents of the buffer.
Is it possible, in PHP, to get all the generated HTML code, at the end of request processing?
What I want to achieve is to be able to retrieve (and, possibly, save/cache) the actual HTML that is about to be sent to users. I can do something similar in ASP.net with a Global.asax filter, that can access to low-level generated html code and modify/access it.
If needed, I can modify the web server settings and/or php interpreter settings (currently the web application runs on Apache+mod_php).
Use output buffering:
<?php
// Start buffering (no output delivered to the browser from now on)
ob_start();
// Generate the HTML
// ...
// Grab the buffer as a variable
$html_output = ob_get_contents();
// If you want to stop buffering and send the buffer to the browser
ob_end_flush();
// OR if you want to stop buffering and throw away the buffer
ob_end_clean();
Potential issues
There is a potential user impact as (depending on your web server) your page output is streamed to the user's browser as it's outputted (why you can start seeing really large pages before they've finished loading). But if you use the output buffer the user will only see the result after you've stopped buffering and outputted it.
Also, because you're buffering and not streaming your server will need to store what you're buffering which will use up additional memory (not a problem unless you're generating really large pages that exceed the memory limits of your PHP memory limit).
To avoid running out of memory you can chunk your buffering and write it to disc (or flush it to the user) at specific chunk sizes using a callback like this:
<?php
// The callback function each time we want to deal with a chunk of the buffer
$callback = function ($buffer, $flag) {
// Cache the next part of the buffer to file?
file_put_contents('page.cache', $buffer, FILE_APPEND & LOCK_EX);
// $flag contains which action is performing the callback.
// We could be ending due to the final flush and not because
// the buffer size limit was reached. PHP_OUTPUT_HANDLER_END
// means an ob_end_*() function has been called.
if ($flag == PHP_OUTPUT_HANDLER_END) {
// Do something different
}
// We could echo out this chunk if we want
echo $buffer;
// Whatever we return from this function is the new buffer
return '';
};
// Pass the buffer to $callback each time it reaches 1024 bytes
ob_start($callback, 1024)
// Generate the HTML
// ...
ob_end_clean();
I think what you would want to use is output buffering! At the start of your page use: ob_start();
At the end of the page you send to the client / browser using something like : ob_end_flush();
Before it is sent you can record that buffer to the db or text file
Is there any command to get the output and erase the buffer without turning it off?
eg.
ob_start();
include 'first_page.php';
$first_page = ob_get_clean();
ob_start();
include 'second_page.php';
$second_page = ob_get_clean();
ob_start();
....
Is there a function available so I don't have to turn on output buffering every time?
I know this is an old question but I was looking for an answer to this question and wanted to post the answer based on comments posted here.
It looks like the answer is no, there is no single command to get the output buffer and erase it without turning it off. However, instead of repeatedly starting a new buffer, you could just erase the current buffer with ob_clean() in between calls of ob_get_contents()
For example:
ob_start();
include 'first_page.php';
$first_page = ob_get_contents();
ob_clean();
include 'second_page.php';
$second_page = ob_get_contents();
ob_end_clean();
I'm having a hard time figuring out the problem in the following code, I really need a solution to this.
Consider the following code :
<?php
//starting a new output buffer, with a GZIP compression
ob_start("ob_gzhandler");
//this goes into the buffer
echo "Hi";
//grabbing the buffer's content
$content = ob_get_contents();
//cleaning the buffer
ob_clean();
//we're still inside the buffer, show the content again
echo $content;
This code fails to output "Hi", instead I see "‹óÈM", what have done that broke correct buffering? Knowing that once I remove "ob_gzhandler", the buffering is correct and everything is fine. I don't want to create another buffer and destroy the current one. I just want to clean the current one using ob_clean.
Any ideas? Thanks in advance.
Thank you for your answer, I figured out why, GZIP is insalled on my machine by the way, it's that when setting ob_gzhandler, the buffer is compressed chunk by chunk, so when using ob_get_contents(), parts of the last chunck are missing, and I end up getting weird output.
To correct that behaviour (or at least to bypass it), open a second output buffer, and leave the one with gzhandler() alone.
Like this
ob_start("ob_gzhandler");
ob_start();
Now the second one isn't compressed, I can do whatever I want with it (hence get its content, clean it etc). The content will be compressed anyway given that a higher level output buffer with gzhandler is opened.
Maybe you don't have gzip compression enabled/installed on your machine.
Tried your code and got something like that. I don't have gzip installed on my machine, try this:
It's your code but with a condition, if gzip doesn't start, the buffer starts.
//starting a new output buffer, with a GZIP compression
if (!ob_start("ob_gzhandler")) ob_start();
//this goes into the buffer
echo "Hi";
//grabbing the buffer's content
$content = ob_get_contents();
//cleaning the buffer
ob_clean();
//we're still inside the buffer, show the content again
echo "<pre>"; echo $content; echo "</pre>";
ob_end_flush();
If you get "Hi", maybe gzip is not installed.
For some time (serveral nights..) I've been trying to get a time-expensive script to output simple dots so I know it's still processing the script. Basically it's a cronjob which is going to run nightly to update cache-keys in a memcache server.
No matter what I try I can't get PHP to output the current buffer. What I want is to send the echo'd dots while processing the script. What am I missing to get it to work? I've also tried the flush() function... and also to use ini_set("output_buffering", 1024);
At the moment this is my set up:
# clean all open buffers
while(ob_get_level() != 0)
{
ob_end_clean();
}
ob_start();
// Several loops, taking some minutes...
for( ..loopconditions ..){
echo ".";
ob_flush();
}
ob_end_clean()
Are you debugging this in a browser? If so, it may not be a problem with the output buffering at all.
Every browser has a buffer of it's own and ultimately it decides when to start flushing it.
Mentioned in the manual page for flush():
flush() ... has no effect on any client-side buffering in the browser.
Even the browser may buffer its input before displaying it. Netscape, for example, buffers text until it receives an end-of-line or the beginning of a tag, and it won't render tables until the tag of the outermost table is seen.
Some versions of Microsoft Internet Explorer will only start to display the page after they have received 256 bytes of output, so you may need to send extra whitespace before flushing to get those browsers to display the page.
IIRC, if you're using php-cgi, output buffering doesn't work.
In console, it is easier to use PEAR Console_ProgressBar. It will do it for you.
Example from the docs:
<?php
require_once 'Console/ProgressBar.php';
$bar = new Console_ProgressBar('[%bar%] %percent%', '=>', ' ', 80, 7);
//do some processing here
for ($i = 0; $i <= 7; $i++) {
$bar->update($i);
sleep(1);
}
echo "\n";
?>
[=======================================> ] 57.14%
More examples in:
http://pear.php.net/manual/en/package.console.console-progressbar.php#example-124
http://pear.php.net/manual/en/package.console.console-progressbar.php#example-125