I'm having some problems with the output buffer. I am buffering my script and printing the result using a callback. The problem is that if a error is thrown at any point, nothing is being shown and I am getting a blank screen. I have tried setting my own custom error handlers but nothing seems to work. I have a feeling this is because the errors are causing my buffer to call the callback method instead of my error handler. Either that or it's because I have the error handler as a static method, but changing that causes issues elsewhere.
I'd really appreciate any help because this one has me stumped!
public function constructor()
{
ob_start(array(__CLASS__, 'render'));
self::$buffer_level = ob_get_level();
set_error_handler(array(__CLASS__, 'exception_handler'));
set_exception_handler(array(_C_LASS__, 'exception_handler'));
RUNNING MY SCRIPT HERE
ob_end_flush();
}
public static function exception_handler($exception, $message = NULL, $file = NULL, $line = NULL)
{
while (ob_get_level() > self::$buffer_level)
{
ob_end_clean();
}
echo $exception.' - '.$message.' - '.$file.' - '.$line.'<br/>';
}
_C_LASS__
Looks like you misplaced a _ there
Damn, that is actually a typo which isn't in the script, so that isn't what is causing the problem. Good spot though!
Related
I am new to CodeIgniter, but am very familiar with MVC frameworks such as Symfony.
I am making a change to a custom helper function, where I am retrieving data from the db. I do not think the DB retrieval is working, but I am not getting any errors. The helper function is simply ignoring errors. There are no errors in the log file (log_threshold = 4) and die() is also being ignored.
I am going to post the helper function below, but my question is not what is wrong with my code (if anything), the question is why are the errors and die() being ignored and what can I do to fix this?
function getRates() {
$ci=& get_instance();
$ci->load->database();
$ci->db->select('currency_values.*');
$ci->db->from('version1.currency_values');
$currencyValues = $ci->db->get();
$lastUpdated = strtotime($currencyValues->result()[0]->last_updated);
die(">>> $lastUpdated <<<"); //This gets ignored
if ($lastUpdated > time() - 600)
{
//Code here that SHOULD be running
}
else
{
//Code here that ALWAYS runs, most likely because db retrieval is not working
}
try to use try and catch and print the exception error
try
{
}
catch(Exception $e){
echo $e;
}
There is no way PHP is ignoring die() call. Confirm it by putting few dummy :
echo "1\n"; at multiple places or by
using exit() instead of die(). Though a complete guess, probably the interpreter is reading code from somewhere else. Such case if not that rare.
For the concern of no error being reported and DB retrieval failing, you may use PHP exception handling or set error_reporting to E_ALL.
error_reporting(E_ALL);
ini_set('display_errors', 1);
Is it possible to exit the script, say on a fatal error and still output my buffer? I am using a template system that executes the header/content/footer. So I am trying to make it so it'll stop code executing on the fatal_error() function but still output the buffer template (which sends out the error message to the user while still maintaining the website template.) I use ob_start("ob_gzhandler") and in my fatal_error() function I use ob_flush() and I end up with a white screen when fatal_error() is called. Here's my function
function fatal_error($error_message, $log = true)
{
setup_error($error_message);
ob_flush();
exit();
}
setup_error() tells the script to change the content body to the error message (so it doesn't parse 1/2 the body when the error occurs). All the examples I've looked through says ob_flush() or ob_end_flush() can achieve this, though I'm not having any luck.
Use the set_error_handler() function. This way you can assign a user-defined function, in your case fatal_error(), to execute when PHP encounters an error. You can do whatever you like in your function, including flushing the buffer and exiting.
EDIT:
The following code should do what you want:
set_error_handler('fatal_error', E_ERROR, E_USER_ERROR);
function fatal_error($errno, $errstr, $errfile, $errline)
{
ob_flush();
exit();
}
EDIT 2:
You can trigger an E_ERROR and therefore test the fatal_error() function like so:
trigger_error('This is a test error', E_ERROR);
I would try also adding a call to flush() before the ob_flush(). Sometimes, both are needed.
Whenever PHP outputs an error message it disregards css and a beautifully designed page by outputting the message at the top of the page removing anything that stands in its way.
for example
some code} else {
echo "error, please do something!";
How do I get it to (or ask it nicely) to output the text inside a div that already exists inside my css so that it will obey the formatting and alignment rules that comes with that div.
You can use the following php.ini settings:
error_prepend_string = "<div class='error'>"
error_append_string = "</div>"
Or something to that effect.
EDIT
Actually, I just realized the "error" you're talking about involves an echo/print out. Here's the problem.
You're printing (echoing) the string error DIRECTLY TO the output buffer (which sends the HTML to the browser when you're finished running all your code). echo() and print() sends what you are echoing/printing straight out, unless it's in an output_buffer block (I won't confuse you with details on that).
So, you're managing your regular html/text output in such a way as to NOT print the page content out to the output buffer, but in this case you are using an echo, which sends the string data directly to the buffer AT THAT MOMENT.
For instance:
Your problem in a simple example
<?php
$mystr = "<html>";
$mystr .= "<body><h1>Hello World</h1></body></html>";
echo "<head></head>";
echo $mystr;
?>
Which would give me on output to the browser:
<head></head><html><body><h1>Hello World</h1></body></html>
I am storing the string data, but echoing the HEAD block before I echo the other html data.
What I need to do instead:
<?php
$mystr = "<html>";
$mystr .= "<head></head>";
$mystr .= "<body><h1>Hello World</h1></body></html>";
echo $mystr;
?>
Which would give me on output to the browser:
<html><head></head><body><h1>Hello World</h1></body></html>
I am storing the string output (your error, in this case) until I need to output it later. This is what you need to know, and accomplish in your code.
I would investigate error_reporting(0)/display_errors, error_get_last, and set_error_handler.
http://www.php.net/manual/en/function.error-reporting.php
http://www.php.net/manual/en/errorfunc.configuration.php#ini.display-errors
http://php.net/manual/en/function.error-get-last.php
http://www.php.net/manual/en/function.set-error-handler.php
So that you could stop sending all errors immediately to the output buffer (which is why it's at the top of the page), and then capture, store and present your errors.
error_reporting(0);
set_error_handler('phpLogError');
function phpLogError() {
$error = error_get_last();
if ($error['type'] == 1) {
//do your stuff
}
}
function phpGetLoggedErrors() {
// return your prettified html errors
}
Or, in other words...
php_error_handle.php
<?php
$GLOBAL['_logged_php_errors'] = array();
error_reporting(0);
set_error_handler('phpLogError');
function phpLogError() {
global $_logged_php_errors;
$error = error_get_last();
if ($error['type'] == 1) {
$_logged_php_errors[] = "<span>$error</span>";
}
}
function phpGetLoggedErrors() {
global $_logged_php_errors;
return "<ol><li>".implode('</li><li>',$_logged_php_errors)."</li></ol>";
}
?>
other.php
<?php
require_once 'php_error_handle.php';
// other stuff, pages included/required, etc...
Just make sure this require_once happens at the first line of code.
Extending #mario above, I've used this at the top of my php file (in dev, not production of course!) which works great. Even in Wordpress admin files!
ini_set('error_prepend_string',"<div class='error'>") ;
ini_set('error_append_string',"</div>") ;
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
Try...catch
http://php.net/manual/en/language.exceptions.php
You can make the error echo in your own css.
echo '<div class="yourerrorclass">error, please do something!</div>';
If it is in the wrong place in the output, that is because you output the error too soon. The entire HTML is outputted sequentially by PHP. If you output the error before any of the other HTML, the error will be on the top of the page and will actually make your HTML invalid.
Displaying errors to screen should be entirely suppressed when running in production, instead log them to file for checking, and fixing. There are details, and the suggested settings in the php.ini file.
Well, now that I've gotten a bit further into it, I realize that this is a stupid question, and wrong. Turns out that the author of the legacy code I maintain was hi-jacking the error log to a different file with a php_init statement. The hi-jacking occurred at the same time as the output buffering was turned on, making it appear as though output buffering was throwing away my error messages.
So, Mr. Moderator, feel free to delete this. Thanks to those who answered in good faith.
Given the following PHP script:
<?php
error_log('test');
ob_start();
error_log('test2');
ob_end_flush();
?>
I get the following error log output:
[04-Feb-2010 11:30:38] test
Why is output buffering eating my error messages? How can I make it stop?
Alternately, is there another way to smuggle messages out of an output buffer, or is it simply a black hole?
(Using PHP 5.2.4-2ubuntu5.10)
Exceptions penetrate ob_start() shield
If you want to stop PHP script execution, rather throw an Exception, which will penetrate the ob_start(), ob_end_flush() shield
echo 'before output buffer';
ob_start();
throw new Exception('this will be seen');
ob_end_flush();
Consider creating a Logger class
Don't output directly with your method, rather use a class or a holder which incorporates the log (or error method in your case), eg:
class Logger
{
private $_messages = array();
public function __construct()
{
$this->_messages['errors'] = array();
$this->_messages['debug'] = array();
}
public function error($msg)
{
$this->_messages['errors'][] = $msg;
}
public function debug($msg)
{
$this->_messages['debug'] = $msg;
}
public function getErrors()
{
return $this->_messages['errors'];
}
}
$logger = new Logger();
$logger->error('error1');
ob_start();
$logger->error('error2');
ob_end_flush();
print_r($logger->getErrors());
this way you can rely on the holder object, it will not discard messages and get all errors, that you wanted to display
I've never done this in practice, but this should work:
You would have to build a wrapper around error_log() that
stores the output you are buffering using ob_get_contents()
erases the output buffer using ob_clean()
writes out the error message and ob_flush()es it
writes back the stored output using echo()
I'm having some problems with the output buffer. I am buffering my script and printing the result using a callback. The problem is that if a error is thrown at any point, nothing is being shown and I am getting a blank screen. I have tried setting my own custom error handlers but nothing seems to work. I have a feeling this is because the errors are causing my buffer to call the callback method instead of my error handler. Either that or it's because I have the error handler as a static method, but changing that causes issues elsewhere.
I'd really appreciate any help because this one has me stumped!
public function constructor()
{
ob_start(array(__CLASS__, 'render'));
self::$buffer_level = ob_get_level();
set_error_handler(array(__CLASS__, 'exception_handler'));
set_exception_handler(array(_CLASS__, 'exception_handler'));
RUNNING MY SCRIPT HERE
ob_end_flush();
}
public static function exception_handler($exception, $message = NULL, $file = NULL, $line = NULL)
{
while (ob_get_level() > self::$buffer_level)
{
ob_end_clean();
}
echo $exception.' - '.$message.' - '.$file.' - '.$line.'<br/>';
}
I would suggest turning on error logging in PHP which will send errors to the apache error log by default. You could also try turning on track_errors, but I think the log is the best bet. If you don't have access to the apache log, you might have to log things manually.
Log files and tracing strategies are essential when using output buffering and other "behind the scenes" stuff (like ajax).
You might also have a look at the output_buffering setting. See this article: http://thinkpositivesoftware.blogspot.com/2009/03/have-blank-php-page.html