I use "ob_gzhandler" function for compressing contents. this is my codes:
<?php
ob_start("ob_gzhandler");
?>
<html>
<body>
<p>This should be a compressed page.</p>
</body>
</html>
don't throw any errors, but compressing operation not working!
in "inspect element" isn't "content-encoding : gzip" phrase!
my system information :
Apache/2.4.23 (Win64) PHP/5.6.25 - Port defined for Apache: 80
Php documentation says, that ob_gzhandler requires zlibextension to be installed, so make sure it is true:
if (extension_loaded('zlib')){
echo "zlib installed";
}
If it's installed, you can use ob_gzhandler and content will be compressed. The problem is you don't see HTTP header Content-Encoding: gzip in response headers. This header is not set by your web server, but you can set it from php, by means of header() function:
header('Content-Encoding: gzip');
So, combining these two step you have a solution:
if (extension_loaded('zlib') && !ini_get('zlib.output_compression')){
header('Content-Encoding: gzip');
ob_start('ob_gzhandler');
}
I also check .iniconfiguration. If zlib.output_compression is On, all output will be compressed, so ob_gzhandler is redundant.
This code is valid, but it's not what php sould be used for. Compressing output and setting headers is web server responsibility. Please, read relevant answer, about configuring .htaccess file, so Apache will do a compression and set correct response headers for you.
Gotcha 1
ob_start(ob_gzhandler) needs zero preoutput.
(Assert <? is the very first byte of your file.)
Gotcha 2
ob_start(ob_gzhandler) needs zlib.output_compression_level be between -1 and 9.
First ensure that PHP is correctly configured (no restart of any kind required); verified with PHP 7.3.10:
php.ini
zlib.output_compression = On
zlib.output_compression_level = 9
Secondly there are some weird bits. Don't try to manually set the Content-Encoding header, for some reason that seems to break pages. This code must start before any output (including spaces/tabs) is sent to the client:
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && stristr($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip'))
{
ob_start('ob_gzhandler');
//header('Content-Encoding: gzip');
}
Lastly you must ensure to properly handle "closing" the compression - if it is active:
if (ob_get_level() > 0) {ob_end_flush();}
I tried all of the above and had to change the last ending bit, hopefully this will save someone's sanity.
Related
I am tyring to stop nginx from gzipping a single PHP request. I already have the following:
#ini_set('zlib.output_compression', 'Off');
#ini_set('implicit_flush', 1);
header('X-Accel-Buffering: no');
According to everything I have found, that X-Accel-Buffering alone should disable gzip, however when I load this page from a browser, I can still see the header:
Content-Encoding:gzip
I'm using php7-fpm, nginx 1.10.1, debian8
EDIT:
I did a test using sleep() to delay the output. It looks like header('X-Accel-Buffering: no'); IS working, however it only prevents buffering and not gzipping. I guess gzipping is working as a stream somehow.
I can see that if I output 1,000 bytes, looping over an echo statement with 1 char each, the browser receives about 11kb. If i echo a str_rep x 1000, then much less data is sent. There must be some overhead there.
Regardless, I need to disable gzip so that I can send a large amount of content and measure the download time. If it's gzipped, I don't know what the actual throughput is.
Nginx will not run gzip filter if Content-Encoding header found in answer. So, you can set Content-Encoding: identity header on backend, and nginx will pass it to client without gzip process. identity means "not encoded".
I haven't found any way to disable it explicitly, however I did find that there is a list of default mime-types that will be encoded by the gzip module.
Since the data doesn't have to be read and is just being sent as a speed test, changing the content type to anything other than that list will prevent it from being gzipped.
header('Content-Type: raw/data');
I'm moving a website to a new server. (Old server had php 5.3.2, the new one has php 5.5.9)
Centos, httpd Apache/2.2.26.
I've copied files and it works fine except the only weird thing:
some strange HEX number is inserted before the content of pages:
Also, in the bottom of the page, 0 is inserted after the </html> tag.
I've noticed two things:
1) In my case only two headers are sent from php script:
header("HTTP/1.1 200 OK");
header("Status: 200");
If I comment the first header than It will be ok - no strange numbers.
2) It looks like that number is the number of characters on the page (I've checked it).
And if the page is less then 8000 characters, than the number doesn't appear, but if page has 8001 characters than 1F41 appears
P.S. I was advised to remove all BOM from files. Files were OK - already without BOM. So it's not about BOM.
UPD:
I made a very simple test (index.php):
<?php header("HTTP/1.1 200 OK"); ?>
Lorem Ipsum ... 8000 characters
Everything is OK.
<?php header("HTTP/1.1 200 OK"); ?>
Lorem Ipsum ... 8001 characters
Bug happens 1f41 before Lorem Ipsum.
This is not PHP nor a BOM. You have a problem with Content-Transfer-Encoding.
The server is sending along a Chunked encoding (this is usually done when the Content-Length is unavailable) which the client apparently doesn't know how to handle, or the header combination makes the client believe that it can bypass dechunking.
Therefore, what is actually the "length of next chunk" gets interpreted by the client, and you see it as a hex bit before the content:
05
These
05
Are
03
the
1F
first characters of the senten
03
ce.
instead of
Content-Length: 48
These are the first characters of the sentence.
(I calculated the lengths by eye, they're probably wrong)
The likely cause is that you have some kind of buffering which interferes with Content Encoding. If everything stays in the buffer, all well and good, a Content-Length is available, gets sent and Bob's your uncle. But if you send more than the 8000 bytes of the buffer, the buffer is flushed and something untoward happens. Try looking in the documentation for zlib and output buffering, you might have some conflict in php.ini between what Apache does and what PHP does.
Interesting links that show how exactly 8000 is (was?) a buffer size used in some portions of apache:
https://bugs.php.net/bug.php?id=45945
https://serverfault.com/questions/366996/how-can-the-apache-2-2-deflate-module-length-limit-be-increased
This last link suggests me to suggest you to try checking whether zlib, mod_gzip, ob_gzhandler and/or mod_deflate are enabled, and possibly conflicting, or to try exchanging the one for the other.
Update (as per comment)
Adding the appropriate Transfer-Encoding header fixes the problem.
So what really happened? We know that the output was correctly chunked-encoded (i.e. the chunking itself was correct), and the client was able to interpret it after being told to. So what was missing was simply the knowledge of the content being chunked, which looks absurd and a good bit buggy: for whatever chunked the content had to know it would get chunked (d'oh!), so it had responsibility of adding the appropriate header, and yet it did not (or it did, but something else stripped it), until the OP rectified the situation adding a header himself by hand.
The problem is now solved, but I think there must be still a bug lingering somewhere in the workflow, either in the modules, the application, or in how the headers are processed.
As discussed in the PHP chat room yesterday 9F 1A is the BOM for UTF-16BE Encoding
In my case only two headers are sent from php script:
header("HTTP/1.1 200 OK"); header("Status: 200");
What's going here? Why are you setting both? One is a proper http response, the other is a CGI response. You shouldn't need to set either, as PHP will default to a 200 OK if the script completes. And setting a CGI style header is probably wrong, unless you're definitely running PHP in CGI mode through Apache.
Had this problem for serving HTML as well as plain text.
EXPLICITLY setting header Transfer-Encoding to "chunked"
header("Transfer-Encoding: chunked");
indeed solved the problem (not sure how reliably though).
That Transfer-Encoding header was being added automatically even if i didn't set it - but the problem was still there. Setting the header explicitly in PHP code solved it, but not exactly - see below. Tested using websniffer.cc, PHP 7.4.9, CentOS 7.8
UPDATE: adding the header might confuse some clients. https://securityheaders.com/ failed to connect to the site with this header explicitly set on (regardless of content length)
i am using the Gzip commpressionand Zlib commpression to speed up my website
I have used below code
ob_start("ob_gzhandler");
in common file that are include on all pages and
lib.output_compression = On
But after this i get the error like
"Warning: ob_start() [ref.outcontrol]: output handler 'ob_gzhandler' conflicts with 'zlib output compression' in E:\xampp\htdocs\projects\trunk\index.php on line 2"
Can any one suggest me what's wrong in it?
You should check if the zlib library loaded then clean the turn off output buffering by doing ob_end_clean()
You can add this line in the top of your file :
<?php if (extension_loaded('zlib')){ ob_end_clean(); ob_start('ob_gzhandler');} ?>
Search line below in your php.ini file:
zlib.output_compression = On
change for:
zlib.output_compression = Off
In your php.ini, search 'zlib' and toggle to On
Recommendation : Dont use PHP Zlib compression, Turn it OFF
but try to Turn on Output Buffering
Which helps Processed HTML are Started to Buffer immediately without waiting.. Which helps to speed up some mili secs.
Dont use too much PHP echo for normal HTML codes.
Use
Webserver Gzip compressions
Minify the HTML outputs
Use Opcache and Static cache generators to Speedup your website 100% Gain.
It's the same. You only need to do one of them, not both.
I had the same problem and your answer was very helpful.
Search line below in your php.ini file:
zlib.output_compression = On
change for:
zlib.output_compression = Off
However I could not figure out where to locate the php.ini file or the zlib.
I took a few days off and I looked over the above from a new perspective. My Hosting provider is "Hostinger" http://api.hostinger.in/redir/21246281 they use the New Control Panel and you will access PHP Configuration here:
ps for cpanel users I will give an update if needed.
Here is an example of a php configure page on the Hostinger panel:
PHP Configuration
PHP version
PHP 5.2
PHP 5.3
PHP 5.4
PHP 5.5
PHP 5.6
PHP 7.0
Choose which PHP version you would like enabled for your account.
Zlib Compression
Enabled
Disabled
Whether to transparently compress pages. If this option is set to "On" in php.ini, pages are compressed if the browser sends an "Accept-Encoding: gzip" or "deflate" header. "Content-Encoding: gzip" (respectively "deflate") and "Vary: Accept-Encoding" headers are added to the output. In runtime, it can be set only before sending any output.
Display Errors
Enabled / Disabled This determines whether errors should be printed to the screen as part of the output or if they should be hidden from the user.
Max Input Vars
Here is an example of the php configure admin panel page just make the change. Hope this was helpuful to someone.
goodloktimes#gmail.com
I thought flush(); would work, at least from what Google/Stackoverflow tell me, but on my Windows WAMP (Windows, Apache, MySQL, PHP) system it doesn't work.
Is there some PHP setting I have to set to make flush() work?
Here's my code:
<?php
echo "Fun";
flush();
sleep(5);
echo "<br>Mo";
?>
The code just outputs all together when the script is done executing (after 5 seconds).. I don't want this, I want 'Fun' to show up right away, and then after 5 seconds 'Mo'.
I've tried other combinations of flush like ob_end_flush(); or ob_implicit_flush(true); but nothing is working. Any ideas?
So that's what I found out:
Flush would not work under Apache's mod_gzip or Nginx's gzip because, logically, it is gzipping the content, and to do that it must buffer content to gzip it. Any sort of web server gzipping would affect this. In short, at the server side, we need to disable gzip and decrease the fastcgi buffer size. So:
In php.ini:
. output_buffering = Off
. zlib.output_compression = Off
In nginx.conf:
. gzip off;
. proxy_buffering off;
Also have this lines at hand, specially if you don't have acces to php.ini:
#ini_set('zlib.output_compression',0);
#ini_set('implicit_flush',1);
#ob_end_clean();
set_time_limit(0);
Last, if you have it, coment the code bellow:
ob_start('ob_gzhandler');
ob_flush();
PHP test code:
ob_implicit_flush(1);
for($i=0; $i<10; $i++){
echo $i;
//this is for the buffer achieve the minimum size in order to flush data
echo str_repeat(' ',1024*64);
sleep(1);
}
The script works fine from CLI, displaying "Fun", waiting 5 secs before displaying "<br>Mo".
For a browser the results might be a bit different because:
The browser wont start rendering right away. Getting 3 bytes of data for HTML document isn't enough to do anything, so it'll most likely wait for a few more.
Implicit IO buffering on the lib level will most likely be active until a newline is received.
To work around 1) use text/plain content type for your test; 2) needs newlines, so do an echo "Fun\n"; and echo "<br>Mo\n"; Of course you wont be using text/plain for real HTML data.
If you're using CGI/FastCGI, forget it! These don't implement flush. The Webserver might have it's own buffer.
You can disable all output buffering in PHP with following command:
ob_implicit_flush();
If the problem persists, although you explicitly set
implicit_flush = yes
in your php.ini, you might also want to set
output_buffering = off
which did the trick in my case (after pulling my hair for 4+hrs)
Check your php.ini for output_buffering.
Maybe the problem is Apache here, which also may have buffers...
I have some issues with a PHP file that is not working properly. The Content-type does not get recieved by any browser at all. Firebug interprets the file as text/html instead of css. Here's the file :
<?php
header('Content-Type: text/css; charset=UTF-8');
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'On');
/* CSS goes on from here */
I tested to put a row with echo 'TEST'; before the header line, and was expecting to see the classic "headers already sent" error, but nothing appears!
Normal .css-files are working like a charm however.
What can I do to sort this out?
UPDATE:
Did change default_mimetype = "text/html" to default_mimetype = "text/css" in php.ini and all pages got immediately interpreted as css, so there's must be a way to just send css headers for this file :)
The full file from demand of John:
<?php
header('Content-Type: text/css; charset=UTF-8');
echo 'body {background-color: #000000; }';
?>
UPDATE #2:
Adding ini_set('default_mimetype', 'text/css'); to the PHP file fixes this file, but it doesn't solve the issue that causes this fault...
UPDATE #3:
Tested adding AddType text/css .css to both .htaccess and Apache config. Still no luck. Also tested to send headers separated from charset: header('Content-Type: text/css'); - Still no luck...
UPDATE #4:
Have reinstalled Apache+PHP at the server to see if the problem goes away, but no. Same old, same old...
Check your php.ini file for the output_buffering setting. If it's not set to "off" than PHP is automatically doing output buffering for you. Set that to off and echo something before the header command, and you should see the "classic error".
You shouldn't use the closing ?>. I know this is a controversial suggestion, but too many times people add a return and/or space after it, which gets output to the browser (before the header). There are very few cases where it not using it would cause a problem.
Make sure your file editor doesn't save a BOM in your PHP file.
Try to move error_reporting / ini_set to make them the firsts PHP statements (before header() call). This way you will see all errors (if any). Don't forget to put that OFF in production!
Silly remark, but make sure this file is interpreted as PHP (extension is .php or if not an .htaccess tell the server to interpret as PHP).
Everything else is fine with your code. If it still doesn't work, check your server logs. Maybe something else crashes the execution of this PHP file (invalid MIME or else)...
the reason is because the header function works only if it is the first one to be called!
If you put an echo before, the content type automatically becomes text/html
try to print a CSS code after the header to test if it actually works.
Read this page for more infos
EDIT: did you change your post ? :-)
This is usually caused by a fatal error (ie, syntax error) that causes the script to abort before any of the code is execute (before display_errors can be set through ini_set() at runtime). Try changing display_errors in the php config file (php.ini).
Maybe the function header() is disabled in your configuration?
Test:
print ini_get('disable_functions');
It may be worth checking with curl to see what headers are actually being sent.
Try this from a command line and check for the "text/css":
curl -I http://example.com
Depending on the browser's request headers, PHP could also be sending the output gzipped using output buffering. In the PHP file, try this to check for ob_gzhandler.
print_r(ob_list_handlers());
If it's enabled, check in for zlib.output_compression in your php.ini or Apache configuration.
I found the full file is indented.
<?php
header('Content-Type: text/css; charset=UTF-8');
echo 'body {background-color: #000000; }';
?>
Because the indentation on line 1 outputted 4 spaces, therefore, the header will not work.
This sounds like your webserver is interpreting the script as a normal file. Does it have a .php extension and do other .php files work as expected?
Looks perfectly ok and the line with the echo should definitely generate a warning. Could it be that you're editing the wrong file?
You can try Content-Style-Type: text/css
See the below from the here
<META http-equiv="Content-Style-Type" content="text/css">
The default style sheet language may also be set with
HTTP headers. The above META
declaration is equivalent to the HTTP
header:
Content-Style-Type: text/css
Edit:
At the link , it's mentionned to add AddType text/css .css in the apache config file.
Maybe you can give it a try
Edit2
Look up for 'css' at this link. Someone had the same problem as you. Try sending the header without the charset
I recently had a hair-threatening
problem with Firefox and XHTML 1.0
transitional.
It worked fine with other browsers,
and also with HTML 4.1.
To cut a long story short,
PHP-generated JS and CSS files were
still being reported by the headers as
text/html, while in the HTML they were
text/css and application/javascript;
Firefox having been told the page was
XHTML 1.0 became anal-retentive and
refused to style the page. (I think
the JS still worked but I fixed it
anyway.)
Solution:
header('Content-type: text/css'); and
header('Content-type:
application/javascript');
Edit 3
There was a post about some forms not submitting any data because of an utility called AVG Linkscanner. Since you have reinstalled Apache + php and I assume you didn't reinstall the OS, so you can maybe investigate on this/try by turning some utilities/plugs-ins off.
Wild guess : open your file with something which would display any BOM. If you see some strange characters before <?php you have your problem. Check your current editor options to save UTF-8 file and make it save them without BOM.
Maybe there are issues with caching.
Try this:
header('Content-type: text/css');
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
echo 'body {background-color: #000000; }';
Works for me on an out of the box XAMPP installation and firefox - firebug reports correct content type.
output_buffering = Off in php.ini was the reason for me why it keeps sending Content-Type = text/html. Setting it to 1 solves it.
In my case, I struggled for hours with my code header('text/javascript');, wondering why the response MIME type wasn't being sent. The correct PHP code is header('Content-type: text/javascript');. There is no proper error detection for this programming error in PHP, Apache, the browsers, or the Web Developer Tools.