ob_start() unexpected behaviour in drupal 7 - php

I have written below code in drupal custom module.
I am getting output in $html but it still printing the output of file.
ie: if string "hello" is there in custom-report.php it prints it twice.
ob_start();
require_once('templates\custom-report.php');
$html = ob_get_contents();
echo $html;

Use ob_get_clean() instead of ob_get_contents()
You must clean and close your output buffer.
The following will:
1.) Save the contents 2.) Output them only when you need them.
ob_start();
require_once('templates\custom-report.php');
$html = ob_get_clean();
echo $html;
ob_get_contents()
This will return the buffer contents but does not erase the output from the buffer.
ob_get_clean()
This will return the buffer contents, clean the output buffer, and end output buffering.
The code from your question has this undesired effect:
1.) Output buffer is saved but left open. 2.) echo $html sends your saved copy of the output buffer contents. 3.) PHP automatically flushes open output buffer contents when it reaches the end of a script. So your output is sent a second time.
This is a fantastic resource for Output Buffer questions:
http://www.tuxradar.com/practicalphp/13/3/0

Related

Output buffering not working or making any sense

I am absolutely stumped here. I must either be missing something very simple or dont understand how this works.
Output buffering does not work at all on MAMP PRO, all contents are simply being displayed on the page and nothing goes to the buffer, not even hello world. I have tried every example
I am creating a simple framework and output buffering just does not work.
I have a module class with a function that includes a file and the code simply shows on the page without me even clearing the buffer.
I have checked the php.ini file in both loaded configuration file and the configuration file shows output_buffering = 4096.
I am so confused
Here is the code example:
//index.php
var_dump(ob_start());//returns true
echo "Hello World"; //prints straight to the screen
include MODULES.'/home.php'; //output comes straight out
var_dump(ob_get_contents());//Shows html string
$test = ob_get_contents();
echo $test; //Output gets displayed twice
In PHP.ini:
output_buffering=4096;
ob_get_contents does not clear the buffer so when a script ends it is flushed to the output as usual.
If you only want to get data as string and clear buffer use ob_get_clean()
You can think of output buffering as creating "bookmarks" or "restore points" in output buffer. For example:
buffer is empty
echo 'hello' - output buffer has "hello" string
ob_start() - "bookmark" is created
echo 'world' - output buffer has two lines "hello" and "world" strings
ob_get_contents() - returns output buffer content since last "bookmark" - returns "world", but buffer contents stay the same
scripts ends and flushes whole output buffer to screen
if you use ob_get_clean() instead it returns contents since last "bookmark" and deletes it from output buffer - the buffer has only "hello" in it
EDIT: I know it's very simple and naive explanation but I recall it helped me a lot to grasp the concept.

Save Output of PHP Virtual() to String

Is there a way to get the Output from PHP Virtual()?
ob_start()
virtual();
ob_end_flush();
is in my case not working.
Per the manual http://php.net/manual/en/function.virtual.php:
To run the sub-request, all buffers are terminated and flushed to the
browser, pending headers are sent too.
One way that I can think of is to create a separate file and load that:
// virtual.php
virtual('/path/to/whatever');
Then wherever you want to get the contents, load it up:
// other.php
$string = file_get_contents('http://www.example.com/path/to/virtual.php');
You use obj_end_flush() which stops output buffering and deletes buffered output.
What you would probably want is this:
ob_start();
virtual();
$output = ob_get_clean();
$output contains the buffered output because ob_get_clean() stops output buffering and returns the buffered output instead of deleting it.
PHP manual ob_end_flush()
PHP manual ob_get_clean()

ob_get_contents + ob_end_clean vs ob_get_clean

Is there any difference between these two pieces of PHP?
ob_start();
//code...
$pageContent = ob_get_contents();
ob_end_clean();
someFunction($pageContent);
vs
ob_start();
//code...
$pageContent=ob_get_clean();
someFunction($pageContent);
I am currently using the first block, but I would like to use the second instead if it is functionally equivalent, since it is a bit more concise.
To answer your question:
ob_get_clean() essentially executes both ob_get_contents() and ob_end_clean().
Yes. It is functionally equivalent.
Case 1:
ob_get_contents() + ob_end_clean():
ob_get_contents — Return the contents of the output buffer
ob_end_clean — Clean (erase) the output buffer and turn off output buffering
So, basically, you're storing the contents of the output buffer to a variable and then clearing it with ob_end_clean().
Case 2:
ob_get_clean — Get current buffer contents and delete current output buffer
You're storing the buffer contents to a variable and then the output buffer is deleted.
What you're doing is essentially the same. So, I don't see anything wrong with using the second code-block here, since they're both doing the same thing.
ob_get_contents() can be used to continue the output buffering.
Example:
ob_start();
echo 'Something!';
$html1 = ob_get_contents();
echo 'More to say!';
$html2 = ob_get_contents();
ob_end_clean();
At the end the vars have this content:
$html1 = 'Something!';
$html2 = 'Something!More to say!';
There is one teeny difference between
$stuff = ob_get_clean();
and
$stuff = ob_get_contents();
ob_end_clean();
which is that the latter will throw an E_NOTICE if there is no active output buffer at the time that you call it, and the former won't. Throwing the notice actually seems like the saner behaviour to me, since if you're calling these functions without an output buffer then you're probably doing something wrong!
That the two approaches are pretty much equivalent is explicitly documented on php.net, which says:
ob_get_clean() essentially executes both ob_get_contents() and ob_end_clean().
The warning-throwing behaviour of ob_end_clean is also documented:
If the function fails it generates an E_NOTICE.
Note that there is no similar sentence in the docs of ob_get_contents or ob_end_clean.
If you really want to assure yourself there are no further differences between these functions (there aren't), you can dive into the definitions of ob_get_contents, ob_end_clean and ob_get_clean in the source. There's some weird error handling for impossible cases in ob_get_clean that should never get reached, but besides that, you can see that the behaviours are as described.
Based on the documentation,
ob_get_contents() + ob_end_clean()
is supposed to work the same as:
ob_get_clean()
However, because of a bug in PHP, it doesn't. Roland from nextendweb filed a bug report:
https://bugs.php.net/bug.php?id=76563
If you use ob_start with callback, the callback does not run, if you use ob_get_clean() on the same output buffer. The callback get skipped, which gives unexpected results. I think it is a bug.
So, if you're passing a callback to ob_start(), you'll need to use
$content = ob_get_contents();
ob_clean();
instead of:
$content = ob_get_clean();
Testing on sandbox, you will notice that it affects all PHP versions.

How does ob_get_contents work in Php?

This is a sample code from the book I am reading:
ob_start();
include("{$path}.ini");
$string = ob_get_contents();
ob_end_clean();
$pairs = parse_ini_string($string);
My question is, how does ob_get_contents() know what to get contents from? ({$path}.ini in this situation)?
ob_get_contents simply gets the contents of the output buffer since you called ob_start(). Essentially, an output buffer in PHP catches anything that would have been output to the browser (excluding headers). It's useful in cases where you may need to filter some output, or you're using a PHP method (such as var_dump) that writes output directly to screen, and you would instead like the return value of the method in a string.
In this case, because you're include()ing the .ini file, it's contents will be essentially output to screen, and ob_get_contents() will get the content of the file.
If you were to put echo "I'm a little teapot short and stout"; underneath the include, this would also be included in $string after the body of the .ini file.
In your specific case, however, output buffering is an unnecessary overhead, simply use file_get_contents on the .ini file. I'm not sure why a book would even have this code in it at all.
The "ob" stands for "output buffer". When you call ob_start(), PHP reroutes all output (using echo, etc) to the output buffer. Then you can use the other ob_* functions to retrieve and/or clear the buffer contents.
In your example, it will buffer any output generated by the file referenced by "{$path}.ini". When you include it, its output is added to the buffer, and when you call ob_get_contents(), it retrieves the contents of the buffer.
From PHP:
ob_start — Turn on output buffering
ob_get_contents — Return the contents of the output buffer
ob_end_clean — Clean (erase) the output buffer and turn off output buffering
Now, ob_get_contents can collect all buffer that outputted.
[1] http://www.php.net/manual/en/book.outcontrol.php
ob_get_contents() is getting everything that is echoed after calling ob_start() function, so there is not anything special about {$path}.ini - you are required to echo data you want to collect (yes, even outputs of simple echo or print_r calls will be collected - sometimes useful for debugging simple scripts).
You may understand ob_start() function as a simple redirection from screen to (invisible) PHP internal buffer which is later read by ob_get_contents(). So you will be able to redirect anything that you may see on the screen without calling ob_start() function (even the whole web pages).

Difference between ob_clean and ob_flush?

What's the difference between ob_clean() and ob_flush()?
Also what's the difference between ob_end_clean() and ob_end_flush()? I know ob_get_clean() and ob_get_flush() both get the contents and end output buffering.
the *_clean variants just empty the buffer, whereas *_flush functions print what is in the buffer (send the contents to the output buffer).
Example:
ob_start();
print "foo"; // This never prints because ob_end_clean just empties
ob_end_clean(); // the buffer and never prints or returns anything.
ob_start();
print "bar"; // This IS printed, but just not right here.
ob_end_flush(); // It's printed here, because ob_end_flush "prints" what's in
// the buffer, rather than returning it
// (unlike the ob_get_* functions)
The key difference is
*_clean() discards changes and *_flush() outputs to the browser.
Usage of ob_end_clean()
it is mostly used when you want to have a chunk of html and do not want to output to the browser right away but may be used in future.
Eg.
ob_start()
echo "<some html chunk>";
$htmlIntermediateData = ob_get_contents();
ob_end_clean();
{{some more business logic}}
ob_start();
echo "<some html chunk>";
$someMoreCode = ob_get_content();
ob_end_clean();
renderTogether($htmlIntermediateCode, $someMoreCode);
where as ob_end_flush() will render twice, once for each.

Categories