Output Buffer and die() / exit() function? - php

I hope everyone's holidays are going well.
Another PHP related question here. I am using output buffers in my script, for what I have recently learned is an invalid reason (so I can pass headers later in the script). I now realize that I should be storing all output in a variable or some other sort of storage until I am ready to output at the end of the script instead of using output buffers. Unfortunately, I have already coding these functions and the spontaneous output of html into my pages already. I was hoping to be able to fix this problem in version 2 of the script, as I have strict deadlines to meet with this version.
To the question at hand. I was planning to do this, but apparently die() and exit() functions do not work so well with output buffers? I have exit() after all of my error messages, and instead of ending the execution at that point, it seems the script keeps going due to the output buffer. I have tested this hypothesis by removing the output buffers and the exit() functions work as expected.
Is there a way I change this behaviour, or should I go back to the drawing board and begin replacing my older pages? Also, can someone please explain to me why we should keep output till the end? I'm always interested in learning.
Thanks in advance everyone! Enjoy the last few days of 2010!

While I'll leave the headier and more abstract questions to more intelligent minds than I, I would recommend that you create a wrapper exit() function to simplify the code when you have errors.
i.e-
if(!$good)
{
trigger_error('bleh', E_USER_WARNING);
errorExit();
}
function errorExit()
{
ob_flush();
exit();
}
And replace all your exits with that function call and that way the buffer is flushed and the program will exit at the proper time.

Difference between header and the actual page content is basically only the position where they occur.
As the name suggests, header is in the beginning of the output. After that two carriage/returns (enter symbols) are sent and everything after that is presumed to be content.
Therefore, if you echo something and then want to change the header, it cannot be done. The content part already closed header part. What you would send as new header would now display as plain text (should PHP interpreter not stop you, which it does).
As for the other part of the question, ob_flush is a good solution as noted by Patrick.

Related

Why need use ob_start() with include()?

Why is recommended use ob_start() in PHP language when you need include other PHP (or template) file?
This is bad:
require_once( dirname( __DIR__ ) . '/views/file.php' );
This is good:
ob_start();
require_once( dirname( __DIR__ ) . '/views/file.php' );
$output = ob_get_clean();
return $output;
But i don't get why
There is no such recommendation, use it if you think its necessary.
ob_start() tells PHP to start buffering output, any echo or other output by any means will be buffered instead of sent straight to the client.
This can be used for many purposes, one of them is being able to send headers even after producing output, since the output wasn't sent yet thanks to buffering.
In this particular piece of code you have, you are using output buffer to catch the output generated by your included file and storing it to a variable, instead of sending it to the client.
It would be hard to say without understanding a little more about your program, as well as who is telling you to do this. For one thing, the return $output line at the bottom--what are you returning from?
I can think of many reasons you'd want to include scripts this way.
In PHP, the ob_* functions deal with output buffering, that is, capturing anything that gets printed to the page/screen your PHP code is running in as a string.
This may be necessary because a very common pattern in classic PHP is to write straight HTML outside of any <?php tags. When you output text this way, it gets sent directly to the screen, bypassing any intermediate processing that you may want to do with it. It's also possible that a programmer may want to define all of their includes in one place, so that they can be switched out easily, and then reference the text to be output as a variable later in the script.
It may also be a way to prevent includes that don't output any text from accidentally outputting white space, making it impossible to change headers later on in the script. I've had problems before with a large code base in which every include had been religiously closed with a ?> and may or may not have included white space afterward. This would have solved the problem with comparatively little effort.
In programming, there are often many different ways to do things, and there's not always one of them that's "right." The end goal is to create something that does its job, is maintainable, and can be comprehended by other programmers. If you have to write a couple of extra lines of code in pursuit of maintainability, it's worth it down the line.
ob_start() is a function that begins output buffering, ob_get_clean(); flushes the buffer, and it looks like you are returning it from a function.
This allows any print or echo statements to be added to the buffer, and then all stored to a variable and returned and printed elsewhere in your application.

How does the PHP code execute even without closing the ?> PHP tag?

Following is the code I come to notice from a PHP file:
<?php
# Should log to the same directory as this file
$log = KLogger::instance(dirname(__FILE__), KLogger::DEBUG);
$args1 = array('a' => array('b' => 'c'), 'd');
$args2 = NULL;
$log->logInfo('Info Test');
$log->logNotice('Notice Test');
$log->logWarn('Warn Test');
$log->logError('Error Test');
$log->logFatal('Fatal Test');
$log->logAlert('Alert Test');
$log->logCrit('Crit test');
$log->logEmerg('Emerg Test');
$log->logInfo('Testing passing an array or object', $args1);
$log->logWarn('Testing passing a NULL value', $args2);
You can notice that the closing PHP tag(?>) is not present there but still all the statements within code are working perfect. I'm not getting how this could be possible to execute the code without completion of PHP tag(?>). I researched but didn't get any satisfatory explanation. Can anyone guide me in this regard? Thanks in advance.
The closing tag exists to tell the interpretter that it should stop executing the text and just output it verbatim. Unlike XML, which requires openning and closing tags to match to be valid, the PHP interpretter simply uses the tags to delimit where execution should start and stop.
Just like a PHP file could have no opening tag - meaining that the entire contents would be output, no closing tag is necessary as once the end-of-file is reached execution ends.
While I can't remember any other reason, sending headers earlier than the normal course may have far reaching consequences. Below are just a few of them that happened to come to my mind at the moment:
While current PHP releases may have output buffering on, the actual production servers you will be deploying your code on are far more important than any development or testing machines. And they do not always tend to follow latest PHP trends immediately.
By sending headers inadvertently, you might have introduced a security vulnerability: say, you are doing a redirection, but hence the headers are already sent, the redirection does not work and the rest of the page might be output, thus the visitor may see what she was not supposed to see. While this can be mitigated by using exit, you know the story, only if every one of us utilize good programming habits every time.
Even if letting the visitor stay in the wrong page does not have a security implication, by breaking a session behavior, or in some other ways I've encountered over years, the security and/or session cycle might have taken some sort of blow in the end.
If not security, you may have headaches over inexplicable functionality loss. Say, you are implementing some kind payment gateway, and redirect user to a specific URL after successful confirmation by the payment processor. If some kind of PHP error, even a warning, or an excess line ending happens, the payment may remain unprocessed and the user may still seem unbilled. This is also one of the reasons why needless redirection is evil and if redirection is to be used, it must be used with caution.
You may get "Page loading canceled" type of errors in Internet Explorer, even in the most recent versions. This is because an AJAX response/json include contains something that it shouldn't contain, because of the excess line endings in some PHP files, just as I've encountered a few days ago.
If you have some file downloads in your app, they can break too, because of this. And you may not notice it, even after years, since the specific breaking habit of a download depends on the server, the browser, the type and content of the file (and possibly some other factors I don't want to bore you with).
Bonus: a few gotchas (actually currently one) related to these 2 characters:
Even some well-known libraries may contain excess line endings after ?>. An example is Smarty, even the most recent versions of both 2.* and 3.* branch have this. So, as always, watch for third party code. Bonus in bonus: A regex for deleting needless PHP endings: replace (\s*\?>\s*)$ with empty text in all files that contain PHP code.
From the PHP Manual:
The closing tag of a PHP block at the end of a file is optional, and in some cases omitting it is helpful when using include or require, so unwanted whitespace will not occur at the end of files, and you will still be able to add headers to the response later. It is also handy if you use output buffering, and would not like to see added unwanted whitespace at the end of the parts generated by the included files.

strange thing, ajax response includes whitespace

I ave several JS functions that call different php files with $.ajax jquery method... yesterday everything was fine, but after cleaning up my code, i don't know what i did, but now the ajax response is like "[space]data" instead of "data"..
i could use a trim function in Js but i want to fix the source of the problem...
all my php files have the missing last ?> in order to avoid that, and before <?php i'm sure, just checked, there is no space...
how come did I introduce this error? is the server? the browser?
The funny thing is that yesterday i cleaned my code with JSLINT..! bad idea..
thanks
When I had the same problem it was just a carriage return or space after the closing PHP tag, a surprisingly easy thing to introduce by accident.
Make sure you open the PHP tag at the start of the first line of your script, close it at the end and delete everything after the closed tag (should be easy to spot in a good editor).
I can see no reason why not closing your PHP tag wouldn't just be really annoying.. but thats just me!
I know I'm late this this thread, found it because I had the same issue. I was able to confirm that the although you may clear all the spacing in your callback function it is still possible to get these white-space/carriage returns in your response text (you can even see this in chrome developer tools under the "Network" tab).
So I tested and found that if you put ob_clean(); at the top of your callback function then it clears any of those spaces. I don't know much about this function just that it was mentioned in the codex (http://codex.wordpress.org/AJAX_in_Plugins#Debugging). Hope that helps anyone else that find there way here because of the same issue
If your response from the server includes the extra space, then the php code is the cause. If your response does not include the extra space, then the problem must be in javascript.
Use Fiddler to examine the actual response from the server to see if it really has the space in it. You'll then know for sure if the problem is with PHP or JS. Then you can post the relevant code.

Gradual echoing of content in PHP? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to make PHP generate Chunked response
How can I execute something, display its contents, and continue executing it and showing its contents? I don't want to wait until the script is done to echo its content.
An example of this is on http://www.masswhois.com/. The script doesn't wait for all of the whois data to be returned before it starts showing results!
I'd recommend the following:
// .. inside of loop...
if(ob_get_length()) {
#ob_flush();
#flush();
#ob_end_flush();
}
#ob_start();
This really flushes the content to the server, but the error suppression is also useful to prevent certain configurations throwing (harmless) errors when there is nothing to flush.
Note that this doesn't necessarily prevent other server output modules from doing their own buffering, so output flushing will not be 100% fool-proof on all systems.
http://php.net/manual/en/function.flush.php
You are probably using output buffering. If you turn it off completely or use the ob_flush() you'll get what you want.

PHP warning: headers already sent in Unknown [duplicate]

This question already has answers here:
How to fix "Headers already sent" error in PHP
(11 answers)
Closed 9 years ago.
I'm looking for things that might trigger the following PHP warning:
PHP Warning: Cannot modify header
information - headers already sent in
Unknown on line 0
Turned out that it was the line
ob_start("ob_gzhandler");
that caused the warning. This has been reported and fixed in 2001, it seems, but for some reason it keeps coming back.
It might be a lot of things, but as the others said, it's often just a space lying around somewhere that gets outputted and then a header() command is sent which normally is fine, but not after starting to send content back (potentially just a space in this case).
Using ob_start() stops the output from going out right away by buffering it. So it's a potential solution, or at least way to diagnose where it's coming from as zodeus said.
One common thing that causes those lose spaces are in this scenario.
global.php
<?php
$variable = 1;
$database = 'something else';
?> <-- A space here
<-- Or here
index.php
<?php
require('global.php');
$var = dosomething();
header('Location: http://www.example.com/');
?>
One way to fix that is to remove the ?> at the end of the global.php file. You don't need those, they are only useful if you start putting HTML for example after your PHP code. So you'd have:
<?php
$variable = 1;
$database = 'something else';
And when you do the require(), the space is not outputted before the header().
Just to illustrate the problems with content outputted and headers is that other common case that gives a similar error. It happens when you forget to stop the processing after a redirection using header().
if ($notLoggedIn) {
header('Location: http://www.example.com/login.php');
}
echo 'Welcome to my website'; // this will be outputted,
// you should have an exit()
// right after the header()
I think whats happening is one of the built in php functions is outputting something. I've seen this with a couple of the IMAP functions where they out put just a " " (space character) and it screws things up.
You can thry tracking it down using Xdebug or the Zend debugger, but i f you have neither
try wrapping output buffering around some of the functions you think may be cause it.
ob_start();
callYourFunction();
ob_end_clean();
Do this one function at a time and when the error goes away you'll know which function is cause you the problem, then you can either file a bug report or just leave it in as a hack. But at least then you know what function is cause the issue.
Edit: The fact that is says your output is occurring on line 0 means that it's a C level function doing the output, not any code that's been written using PHP.
Have you checked your files for unintended UTF-8 BOMs?
The error tells you that something has sent output, which would force headers to be sent, because the headers must be written before the body of the http message.
The most common problem I have found is text in headers. vis:
<?php // myfile.php
include 'header.php';
?>
and in header.php:
<?php // header.php
....
?>
What you can't see here is that there is a blank - either a space or CR/LF after the closing '?>'. This is output because the php standard says that anything outside the php tags is output as html.
The solution is to make sure that you make sure to erase everything after the closing '?>'

Categories