CodeIgniter "content encoding error" - php

Does any body has any idea how to find where the leak is that provokes this "Content Encoding Error" with $config['compress_output'] = true in CodeIgniter?
I've trying to debug this error for days, but I can't seem to find where the leak is. LogLevel is at debug but I see no info in the log when this error happens.
So, any ideas how to debug this?
UPDATE
I really don't want to disable the compress_output feature, I just want to see how can I trace where the error is produced
UPDATE2
I've looked over and over again to see if there is any output in the controllers... and there is none, so some where else must be the error provoked. No models/database, just controllers, libraries, helpers and views

This issue is where the output buffering starts. The check for the config variable is in system/core/Output.php in _display(). It starts the gzipped buffering after a lot of code has already run. This leaves the potential for output to have occurred before it buffering starts.
With compress_output set to false it doesn't matter because nothing is encoded. With it set to true you end up with mixed content. Some output is encoded and some is not which causes the compression error.
There are two solutions:
1) You could leave compress_output set to false and add ob_start('ob_gzhandler'); to the top of your index.php file. This will ensure that all output is always gzipped, including errors.
2) The other solution is to add ob_flush(); before ob_start('ob_gzhandler'); in system/Output.php. This will gzip output when there are no errors and serve you unencoded content when there are errors.
I think 2 is the better solution and should be implemented by the CodeIgniter team. But if you don't want to muck with the system code (changes will go away when you upgrade) then 1 is the better solution for you.

This might be a long shot, but if you echo/print database output directly from your controller instead of sending it to the model you'll likely get error messages that have to do with output buffering. Are you echoing from your controller?

Putting the following line in config.php:
$config['compress_output'] = FALSE;
Solves it. The problem in my case was that I sent the post, but it did not recognize the FILLCATEGORIAS function. Inly by changing the $ config [ 'compress_output'] = FALSE; solved it.
THIS problem occurred when we send data using a POST request:
Failed to load resource: net::ERR_CONTENT_DECODING_FAILED
<script type="text/javascript">
$(document).ready(function() {
$("#idEmpresa").change(function() {
$("#idEmpresa option:selected").each(function() {
id = $('#idEmpresa').val();
$.post("<?php echo base_url();?>Admin/fillCategorias", {
idEmpresa : id
}, function(data) {
$("#idCategoria").html(data);
});
});
});
});
</script>

Any error in PHP will break compression.
To test this, in index.php change:
error_reporting(E_ALL);
to
error_reporting(E_ALL ^ E_NOTICE);
Do not echo/print to display output from controller.
Do not use "?>" at the end of controller file.
I hope it helps.
Update:
To check if the output is empty before starting buffering, you can open core/Output.php and add
ob_flush();
before
ob_start('ob_gzhandler');
If there is even a space or an empty line, compression will fail. (check page source from browser). This happens because with $config[‘compress_output’] = true , ob_start('ob_gzhandler') (line 379 in Output.php) is executed, wich will cause a "Cannot modify header information - Headers already sent ..." warning. This warning is the cause of compression failure.
So basically, any echo outside of Output class (json output included) will send headers to client, which will cause "Cannot modify header information - Headers already sent ..." warning, which will cause the "content encoding error".

I had the same problem. After searching, I found that my controller has ?> at end of file. So I removed it and it works perfectly. Here is a link for more detail.

More compliant solution:
$this->output->set_output($data);

Some CPanel lightspeed extension updates create this problem. You can try adding this code in your .htaccess file:
php_flag zlib.output_compression ON

Related

Why I'm not getting a 'Warning: Cannot modify header information - headers already sent by' as I expected to get one?

I'm using PHP 7.1.11 on a machine that runs on Windows 10 Home Single Language edition.
I'm using XAMPP server on my machine.
I'm using following browsers on this machine :
Google Chrome(Version 62.0.3202.94 (Official Build) (64-bit))
Firefox Quantum(57.0.1 (64-bit))
Opera(Version : 49.0.2725.47)
Microsoft Edge 41.16299.15.0
I know the details of header() function and how it works.
But following program is behaving in really a weird way on all of the above four web browsers. Even after sending output to the client the header() function is working.
How can this be possible?
Below is my code(It's getting redirected to the URL I mentioned) :
<!DOCTYPE html>
<html>
<body>
<p>Welcome to my website!</p><br />
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
if($test) {
echo 'Welcome to my website<br />You\'re in!';
} else {
header('Location: http://www.espncricinfo.com');
}
?>
</body>
</html>
I was expecting to get the warning 'Cannot modify header information - headers already sent by' but surprisingly it's getting redirected me to the URL http://www.espncricinfo.com/?
Why?
If you are somehow using output buffering — either manually, or because your PHP is configured to automatically do this — you are still allowed to add headers, so long as the initial buffer has not been flushed.
What output buffering does is what the name hints at: put output in a buffer to be sent at a later stage, in stead of immediately outputting data. Because of this, so long as no body data of the HTTP response message has been sent, you are still able to send header data.
To check whether PHP is configured to automatically buffer output, you can do one of the following:
check the php.ini configuration file and search for the string output_buffering
var_dump( ini_get( 'output_buffering' ) );
phpinfo(); (dumps the whole configuration) and search for the string output_buffering
If output buffering is enabled, the value will either be the buffer size in bytes (if configured as such), or "On" or true, or something to that effect.

ob_start() without an ob_flush()

I hired someone to write an API for me in PHP and MySQL and now have to maintain it myself. I don't know php as well as other languages.
I noticed at the start of most of the php files they have:
ob_start();
I understand that this opens a new output buffer. The thing is that they never flush the buffer. The code had been working fine but I've had a lot of optimization issues, slow server responses, etc.
How is it that they don't have to flush the buffer but the response is still returning?
An example would be:
ob_start();
include "nusoap.php";
include "config.php";
require_once "class.Database.php";
$client = new nusoap_client($config['apiURL'].'/server.php',false, false, false, false, false, 600, 600);
... process the $_GET and build a $result ...
print_r($result);
Obviously the ... process ... is a wide open thing. But I'm not seeing anywhere in there that does any sort of flush or reading the ob contents. I've also searched all the includes and don't see one in there either.
I checked and implicit_flush is set to Off on this server. Since we did move this code from another server possibly on that server it was on. But still currently this API is working on this server.
The reason I said "not that I can find" when someone asked if there was an ob_get_contents() is because there are include files (including nusoap.php) that include other files and while I've grepped through them and tried to trace them, I might have missed something and am still searching. But so far it appears to my eye that no flush or get_contents is happening.
One possible answer is to say "NO, there has to either be an implicit_flush set in the php.ini file, or an implicit_flush() command somewhere, or another flush command somewhere, or getting the contents of the buffer somewhere - or the contents would never output." To me that is what the manual suggests. But sometimes there are loopholes and PHP seems to be a language of loopholes.
SOLVED
Indeed I did a simple test:
<?php
ob_start();
echo "Whats Up Doc!";
?>
and the output is seen in the browser.
PHP ob_start() function works by catching all output to buffer and then implicitly output this buffer on script end.
You may execute ob_end_clean() to discard (clean) buffer.
In Your example 'print_r($result);' will send output to buffer and then PHP interpreter will send buffer to client (http server/console).
PS. Function ob_implicit_flush() has different meaning. It just flush buffer on every output call (like print or echo), and do not have effect on script finish.

Problems Unit Testing with Simpletest

I am using PHP and simpletest for unit testing. My tests work fine until I try and set the cookie
try{
setcookie($name,$cookie,$cookie_expires );
}catch Exception($e){
blah
}
The exception is thrown because simpletest has already written out header information so I get the following:
Unexpected PHP error [Cannot modify header information - headers already sent by (output started at /tests/simpletest/reporter.php:43)] severity [E_WARNING] in [blah_code.php line 280]
I've seen vague explanations on catching this with $this->expectException(new Exception()); but no further documentation or examples that work. Could someone provide a working example or point me to documentation? To be clear. This is NOT my code producing the output but rather SimpleTest.
One way to get around this is by using output buffering.
You can turn it on globally in PHP's configuration (and possibly in .htaccess), or you can use ob_start() and its related functions (ob_get_clean(), ob_end_flush(), etc). For example:
ob_start();
// your SimpleTest here.
// your header/ cookie manipulation here.
And then:
ob_end_clean(); // Stop buffering and dump everything (don't echo).
ob_end_flush(); // Stop buffering and echo out the buffer.
ob_get_clean(); // Stop buffering and return everything as a string.
Or any of the other related functions. I believe PHP calls ob_flush() at the end of a file if you don't.
You get this error when you have output before (header functions) setcookie($name,$cookie,$cookie_expires );.
Make sure you don't have any echos or html or text or anything(NOT EVEN A SPACE) before <?php of setcookie($name,$cookie,$cookie_expires );.

Displaying custom error page in PHP for errors which can't be caught by set_error_handler

I would like to be able to discard a partially rendered page and show an error page in PHP.
I already know about set_error_handler(), but it can only trap certain types of errors. I would like to know how to show an error page when an error type which can't be trapped by set_error_handler() is raised.
Unfortunately, it seems that the following code, when run with PHP 5.3.2 on Apache 2.2, doesn't do what I would expect it to do:
<?php
// Start the output buffer
ob_start();
// Output something into the buffer.
// I only want this to be displayed if I call one of the
// ob_flush functions or echo the buffer myself later.
echo "yep";
// Call a function I know not to exist in order to raise
// an error which cannot be trapped by set_error_handler()
// and would, if display_errors was On, output "Fatal
// error: Call to undefined function fwee()..."
function_which_does_not_exist();
// This will never be executed.
$out = ob_get_clean();
The output of the script is:
yep
Whereas I would expect it to output nothing (or spew error info and only error info if display_errors() is on).
I have confirmed using LiveHTTPHeaders that PHP 5.3.2 does send a 500 error to the browser when display_errors is off (and a 200 when it's on) using the version of apache supplied by MacPorts, but it only ever spits 200s when using PHP 5.3.1 on XAMPP.
I tried setting ErrorDocument 500 "test" in the apache configuration (confirmed to be working by doing the same for 404) but PHP never shows the custom error, even when the entire contents of the script is just header('HTTP/1.1 500 Internal Server Error');
I'm not sure what else to do to make sure a partially rendered page is replaced with a simple error.
I can also confirm that this happens in the Yii framework. If I edit the view for the "about" page in the blog demo to have a line which reads <?php echo function_which_does_not_exist() ?>, I get a partially rendered page.
You could pass ob_start the name of a callback function, that is executed before the output is flushed on ob_get_clean().
This callback function seams to be executed even if an error occured on the page.
This way you could do something like this:
<?php
$endReached = 0;
function outpu_cb($buffer) {
global $endReached;
if ($endReached) return $buffer;
else return 'Your error message';
}
// Start the output buffer
ob_start('outpu_cb');
// Output something into the buffer.
// I only want this to be displayed if I call one of the
// ob_flush functions or echo the buffer myself later.
echo "yep";
// Call a function I know not to exist in order to raise
// an error which cannot be trapped by set_error_handler()
// and would, if display_errors was On, output "Fatal
// error: Call to undefined function fwee()..."
function_which_does_not_exist();
// This will never be executed.
$endReached = 1;
echo ob_get_clean();
?>
I think the only right way to do this is by using correct output buffering, than you don't have to rely on specific webserver or browser behaviour.
Best you'd use a MVC framework to handle this for you. All output is buffered until all systems are go, so when an error occurs you can take another route, clear the current buffer and display some nice error message.
You can also use the ob_*() family of functions.
You have to call ob_start() as the very first thing in your script (well, before any output is generated)
Install an error_handler to fetch errors
When an error occured, clean the buffer and re-route your app logic to display some nice userfriendly error message
If your talking about E_FATAL or other such errors yes you can catch them with a custom error handler using set_error_handler().
All you need to add is a shutdown function.
// Set the error handler
set_error_handler(array('error', 'handler'));
// Catch E_FATAL errors too!
register_shutdown_function(array('error', 'catch_fatal'));
// Set the exception handler
set_exception_handler(array('error', 'exception'));
// Manually return a new exception
function catch_fatal()
{
if($e=error_get_last())Error::exception(new ErrorException($e['message'],$e['type'],0,$e['file'],$e['line']));
}
Take a look at http://micromvc.com or http://kohanaphp.com/ to see how it's done.
An old question, but for the record I'd suggest avoiding this issue rather than handling it.
My own approach is to build the response in a response object rather than echoing it as you go along, and only echo the output once the full response has been processed without error. This requires a template system that parses your template and builds your response into a string, in contrast to a classic PHP template which echoes output from your placeholders.
This way you entirely avoid PHP's crufty management of the output cache in error states.

Errors inside of output buffer

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

Categories