PHP server (Apache) only compresses JSON output with ob_start - php

So I’ve setup a web server for a REST API and I’m coding it in PHP.
I’ve set Apache so that I can use gzip compression:
<IfModule mod_mime.c>
AddType application/x-javascript .js
AddType text/css .css
</IfModule>
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript application/json
<IfModule mod_setenvif.c>
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
</IfModule>
<IfModule mod_headers.c>
Header append Vary User-Agent env=!dont-vary
</IfModule>
</IfModule>
Then using curl I test which headers I are sent back:
HTTP/1.1 200 OK
Date: Sat, 24 Oct 2015 23:24:34 GMT
Server: Apache/2.4.10 (Unix) OpenSSL/1.0.1j PHP/5.6.3 mod_perl/2.0.8-dev Perl/v5.16.3
Last-Modified: Sat, 24 Oct 2015 23:04:13 GMT
ETag: "b9413-522e1bf1eb540-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 4204
Content-Type: text/plain
Great, that seems to work. However, when I run my test script (index.php) which creates a resource and returns the object (or error) in a JSON response, I get the following:
HTTP/1.1 201 Created
Date: Sat, 24 Oct 2015 23:26:01 GMT
Server: Apache/2.4.10 (Unix) OpenSSL/1.0.1j PHP/5.6.3 mod_perl/2.0.8-dev Perl/v5.16.3
X-Powered-By: PHP/5.6.3
Location: api.domain.com/rest/v1/users/12345
Connection: close
Content-Language: en
Vary: User-Agent
Content-Type: application/json; charset=utf-8
Why doesn’t the JSON response return compressed? I purposely return >700kb just to make sure it compresses something.
I explicitly set the content-type header in my server before returning a JSON response. Is this not enough? I’m guessing the fact that it’s a PHP file may be the problem but I’m not experienced with Apache enough to know if it would be a problem/the fix.
However, if I add ob_start("ob_gzhandler”); to my PHP code, the content is compressed.
Also, it’s worth mentioning the .txt and index.php are in the same folder.

Try next (be sure filter_module is installed):
<IfModule filter_module>
FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/json'"
</IfModule>

Related

can't cache static files using htaccess

I am new to caching and i am trying to test how files would be cached so i have created a simple php web page to test if i can cache the css file:
<!doctype html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1 id="heading">Test</h1>
</body>
</html>
and i have created an htaccess file then added these lines from here
# ----------------------------------------------------------------------
# | Expires headers |
# ----------------------------------------------------------------------
# Serve resources with far-future expires headers.
#
# (!) If you don't control versioning with filename-based
# cache busting, you should consider lowering the cache times
# to something like one week.
#
# https://httpd.apache.org/docs/current/mod/mod_expires.html
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
# CSS
ExpiresByType text/css "access plus 1 year"
</IfModule>
then i tried to change style to check if it is cached but style changes on every load which means that there is no caching, then i thought my be it is the local server configurations so i moved to live one and agian still the same and it tested headers with this site
and i got this:
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Sun, 24 Sep 2017 13:02:51 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: max-age=0
Expires: Sun, 24 Sep 2017 13:02:51 GMT
Vary: Accept-Encoding,User-Agent
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
EDIT:
I have found that mode_expires was not active on localhost and i enabled it but still facing the problem
try adding this part :
<IfModule mod_headers.c>
<FilesMatch "\.(ico|jpe?g|png|gif|swf|css|gz)$">
Header set Cache-Control "max-age=2592000, public"
</FilesMatch>
<FilesMatch "\.(js)$">
Header set Cache-Control "max-age=2592000, private"
</FilesMatch>
<filesMatch "\.(html|htm)$">
Header set Cache-Control "max-age=7200, public"
</filesMatch>
# Disable caching for scripts and other dynamic files
<FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$">
Header unset Cache-Control
</FilesMatch>
</IfModule>

I'm not able to cache my PHP rewritten CSS file

I have a php file that is renamed in htaccess as a css file. The reason being, is because I have some styles and colors which change based on some admin options.
Anyway, I am trying to allow a visitor's browser to cache the file. Here's what I have:
style.php:
header("Content-type: text/css; charset: UTF-8");
// Start normal CSS styles...
.htaccess:
RewriteRule ^assets/css/min/([a-zA-Z0-9\._-]+)/([a-zA-Z0-9\._-]+)/([a-zA-Z0-9\._-]+)\.css$ assets/css/min.php?style=$1&layout=$2&ver=$3 [L,QSA]
# Compress
AddOutputFilterByType DEFLATE text/css
# Cache for 1 week
<FilesMatch ".(css)$">
Header set Cache-Control "max-age=604800"
</FilesMatch>
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType text/css "access plus 1 week"
</IfModule>
In the page head:
<link rel="stylesheet" href="http://example.com/assets/css/min/blue/flat/0.9.2.css">
Each time a new page is loaded, the page contents are requested. These are the headers I receive:
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 13881
Content-Type: text/css; charset: UTF-8;charset=UTF-8
Date: Sat, 20 Feb 2016 22:49:17 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive: timeout=5, max=94
Pragma: no-cache
Server: Apache/2.4.16 (Unix) OpenSSL/1.0.1p PHP/5.6.12 mod_perl/2.0.8-dev Perl/v5.16.3
Vary: Accept-Encoding,User-Agent
X-Powered-By: PHP/5.6.12
Your mod_expires config applies to files based on their mimetype as perceived by the webserver. Unless you've done some major surgery on the webserver config elsewhere, the webserver will not associate the text/CSS mimetype with files ending in .php (and if it did, much further hacking would be required to get them processed by the PHP parser). The header set by your PHP script is irrelevant to this process.
While it is possible to force mod_expires to add caching headers to the response, you'll also have to use mod_headers to remove the values PHP sets; when a browsers receives multiple conflicting caching instructions, it will resort to the shortest expiry time expressed in them.
Hence, to make the content cacheable, you should emit the caching information directly from the PHP script. E.g.
header('Cache-control: max-age=604800; private');
But basing the expiry time on the access time is not the best solution.

NGINX and PHP Gzip compression not working in browser but works in cURL

There is a peculiar issue happening in my NGinx and PHP Setup.
My Test URL : http://104.194.26.13:2002/a.php
I am using PHP with NGinx (FCGI). To compress the data I am using :
<?php
ob_start('ob_gzhandler');
phpinfo();
?>
When accessed via the browser it shows :
Vary: Accept-Encoding
But there is no Content-Encoding and the size of the downloaded data shown in Firebug is that of a non-compressed data.
When accessed from CLI using curl :
curl -H "Accept-Encoding: gzip" "http://104.194.26.13:2002/a.php"
There are some gbiresh characters suggesting it did encode. If you save the output with the above command the size is 17.5 KB instead of the 75 KB when accessed via the browser.
Here is the full headers received from my a.php file :
Connection: keep-alive
Content-Length: 75550
Content-Type: text/html
Date: Fri, 15 Jan 2016 05:37:43 GMT
Server: nginx
Vary: Accept-Encoding
X-Powered-By: PHP/5.5.27
What could be possibly wrong ?
Which browser are you using, because Chrome 47.0.2526.106 m shows this:
Now, as stated in the comments, why don't you try and compress it directly from Nginx? By leveraging gzip compression within the nginx config:
# enable gzip compression
gzip on;
gzip_min_length 1100;
gzip_buffers 4 32k;
gzip_types text/plain application/x-javascript text/xml text/css;
gzip_vary on;
# end gzip configuration
Source
Here are my request headers:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:104.194.26.13:2002
Referer:http://stackoverflow.com/questions/34805168/nginx-and-php-gzip-compression-not-working-in-browser-but-works-in-curl/34805312?noredirect=1
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36

PHP Caching Files (.htaccess)

I have the following code which I am using for my website. I would like to know if this code is correct in order for me to effectively cache me pages and files. I have tried to use tools to check this but some say they don't see that I am caching.
<ifModule mod_headers.c>
# 1 Month
<filesMatch ".(ico|gif|jpg|jpeg|png|pdf)$">
Header set Cache-Control "max-age=2419200"
</FilesMatch>
# 1 Week
<filesMatch ".(css|js)$">
Header set Cache-Control "max-age=604800"
</FilesMatch>
# 1 Day
<filesMatch ".(htm|html)$">
Header set Cache-Control "max-age=86400"
</FilesMatch>
</ifModule>
Catching is the automatic mechanism of the browsers. When a page is loading, browser checks the cache for static files like js, css, images..., if they are not available browser will pus them into cache.
To determine whether the file is cached or not, check the firebug console and clik on request link.
here you can see information like
Accept-Ranges bytes
Cache-Control max-age=290304000, public
Content-Encoding gzip
Content-Length 2824
Content-Type application/javascript
Date Thu, 11 Jul 2013 10:15:06 GMT
Expires Fri, 12 Jul 2013 10:15:06 GMT
Last-Modified Thu, 03 Jan 2013 16:05:54 GMT
Server Apache
Vary Accept-Encoding,User-Agent

Problems with ob_gzhandler and CSS files

I've created a page that will take css (or javascript) files and output them as one file. I have noticed that Firefox and Internet Explorer will both fail to send the "If-Modified-Since" header at any time when I compress the output using ob_gzhandler:
if(!ob_start("ob_gzhandler")) ob_start();
The initial headers (Host and referrer changed in sample):
Response Headers
Cache-Control public, must-revalidate, maxage=4838400
Connection keep-alive
Content-Encoding gzip
Content-Length 87281
Content-Type text/css; charset: UTF-8
Date Wed, 12 Dec 2012 16:04:32 GMT
Expires Wed, 06 Feb 2013 16:04:32 GMT
Last-Modified Fri, 12 Oct 2012 13:47:18 GMT
Pragma public
Server Apache
Vary Accept-Encoding
X-Cache MISS from localhost
X-Powered-By PHP/5.3.13
Request Headers
Accept text/css,*/*;q=0.1
Accept-Encoding gzip, deflate
Accept-Language en-gb,en;q=0.5
Authorization Basic cmVkZnVzZTpyM2RmdXMz
Cache-Control no-cache
Connection keep-alive
Cookie PHPSESSID=e73355c49f06a059c22d7f02687dc51b
DNT 1
Host example.com
Pragma no-cache
Referer http://example.com/
User-Agent Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/17.0
And the following headers are sent on refresh (Host and referrer changed in sample):
Response Headers
Cache-Control public, must-revalidate, maxage=4838400
Connection keep-alive
Content-Encoding gzip
Content-Length 87245
Content-Type text/css; charset: UTF-8
Date Wed, 12 Dec 2012 16:09:11 GMT
Expires Wed, 06 Feb 2013 16:09:11 GMT
Last-Modified Fri, 12 Oct 2012 13:47:18 GMT
Pragma public
Server Apache
Vary Accept-Encoding
X-Cache MISS from localhost
X-Powered-By PHP/5.3.13
Request Headers
Accept text/css,*/*;q=0.1
Accept-Encoding gzip, deflate
Accept-Language en-gb,en;q=0.5
Authorization Basic cmVkZnVzZTpyM2RmdXMz
Cache-Control max-age=0
Connection keep-alive
Cookie PHPSESSID=e73355c49f06a059c22d7f02687dc51b
DNT 1
Host example.com
Referer example.com
User-Agent Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/17.0
If I switch from using ob_gzhandler to a standard ob_start() then it works fine and returns a 304 as expected on the second load.
Another issue that I think is related is that when viewing from an android device, the css doesn't get applied for either the stock browser or for Dolphin Browser, but is fine for Firefox for Android. This is also resolved by disabling the ob_gzhandler

Categories