Serving PHP files with GZip

Experts,

Im trying to utlilze the GZIP class to serve my php files, but cant seem to get it working. I have attached a code snippet of how im am including it. Any suggestions as to what im doing wrong would be appreciated.

To test if it is working, i am using the 'live headers' addon from firefox. And testing the webpage http://www.mygolfbook.co.uk
(also any comments / suggestions on improving/opotmizing wouldnt go a miss :) )

Regards
easynow
<?php
ob_start();
include('class.gzip_encode.php');
....
BODY (for info the class file above sits in the same directory)
....
<?php
new gzip_encode();
?>

Open in new window

LVL 12
Dean OBrienAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

karoldvlCommented:
I would offload gzip compression to the webserver. IMHO, it's easier to maintain after you configure it correctly.

As to the PHP side of this, there's an article explaining some alternatives:
http://www.webcodingtech.com/php/gzip-compression.php

Pertaining to gzip_encode class - I presume you use TYPO3, right? If not, please provide a link to the class source.
Dean OBrienAuthor Commented:
Hi Karoldvl

Thanks for your reply.
With regards off loading the compression to the server, i dont have control over this as im using a hosting compay.

I will review the link you have posted and see if i can try the alternative method. However for the time being please find attached the class source.

Also, im not sure what you mean by TYPO3 (perhaps this is what im missing...)

Regards
Easynow
<?php

// News: I had once said that when PHP4.0.5 comes out I will reccomend the built in
// ob_gzhandler over my code unless you are generating flash or images on the fly.
//
// I was wrong. PHP4.0.5 is out and ob_gzhandler doesn't work for me.

// Note: This is rather cool: http://Leknor.com/code/gziped.php
// It will calculate the effects of this class on a page.
// compression level, cpu time, download time, etc

// Note: this may better for some sites: 
// http://www.remotecommunications.com/apache/mod_gzip/
// I've read that the above doesn't work with php output.

class gzip_encode {
    /*
     * gzip_encode - a class to gzip encode php output
     *
     * By Sandy McArthur, Jr. <Leknor@Leknor.com>
     * 
     * Copyright 2001 (c) All Rights Reserved, All Responsibility Yours.
     *
     * This code is released under the GNU LGPL Go read it over here:
     * http://www.gnu.org/copyleft/lesser.html
     * 
     * I do make one optional request, I would like an account on or a
     * copy of where this code is used. If that is not possible then
     * an email would be cool.
     *
     * How to use:
     * 1. Output buffering has to be turned on. You can do this with ob_start()
     *    <http://php.net/manual/function.ob-start.php> or in the php config
     *    file. Nothing bad happens if output buffering isn't turned on, your
     *    page just won't get compressed.
     * 2. Include the class file.
     * 3. At the _very_ end of your script create an instance of the encode
     *    class.
     *
     * eg:
     *    ------------Start of file----------
     *    |<?php
     *    | ob_start();
     *    | include('class.gzip_encode.php');
     *    |?>
     *    |<HTML>
     *    |... the page ...
     *    |</HTML>
     *    |<?php
     *    | new gzip_encode();
     *    |?>
     *    -------------End of file-----------
     *
     * Things to note:
     * 1. There is no space before the beginning of the file and the '<?php' tag
     * 2. The ob_start() line is optional if output buffering is turned on in
     *    the main config file.
     * 3. Turning on and off output buffering just won't work.
     * 4. There must be nothing after the last '?>' tag at the end of the file.
     *    Be careful of a space hiding there.
     * 5. There are better ways to compress served content but I think this is
     *    the only way to compress php output.
     * 6. Your auto_prepend_file is a good place for the ob_start() and
     *    your auto_append_file is a good place for new gzip_encode().
     * 7. If you put new gzip_encode() in your auto.append file then you can
     *    call ob_end_flush() in your script to disable compression.
     *
     * This was written from scratch from info freely available on the web.
     *
     * These site(s) were useful to me:
     *    http://www.php.net/manual/
     *    http://www.ietf.org/rfc/rfc2616.txt (Sections: 3.5, 14.3, 14.11)
     *
     * Requirments:
     *    PHP 4.0.1+:    I use the '===' operator, and output buffering, crc32();
     *    zlib:        Needed for the gzip encoding. (Odds are you have it)
     *
     * Benchmarks:
     *    Take a look at http://Leknor.com/code/gziped.php and feed it a page to
     *    get an idea of how it will preform on your data or page.
     *
     * To Do:
     * 1. I have reports of no content errors. I can't seem to duplicate this.
     *    Please visit my discussion boards if you think you may be able to help
     * 2. The Accept-Encoding isn't handled to spec. Check out 14.3 in RFC 2616
     *    to see how it should be done.
     *
     * Change Log:
     *    0.67:    Added Vary header to aid in caching.
     *    0.66:    Big bug fix. It wouldn't compress when it should.
     *    0.65:    Fix for PHP-4.0.5 suddenly removing the connection_timeout() function.
     *    0.62:    Fixed a typo
     *    0.61:    Detect file types more like described in the magic number files, also
     *        added detection for gzip and pk zip files.
     *    0.6:    Detect common file types that shouldn't be compressed, mainly
     *        for images and swf (Shockwave Flash doesn't really accept gzip)
     *    0.53:    Made gzip_accepted() method so everyone can detect if a page
     *        will be gzip'ed with ease.
     *    0.52:    Detection and graceful handling of improper install/missing libs
     *    0.51:    Added FreeBSD load average detection.
     *    0.5:    Passing true as the first parameter will try to calculate the
     *        compression level from the server's load average. Passing true
     *        as the second parameter will turn on debugging.
     *    0.4:    No longer uses a temp file to compress the output. Should speed
     *        thing up a bit and reduce wear on your hard disk. Also test if
     *        the http headers have been sent.
     *    0.31:    Made a small change to the tempnam() line to hopefully be more
     *        portable.
     *    0.3:    Added code for the 'x-gzip'. This is untested, I don't know of
     *        any browser that uses it but the RFC said to look out for it.
     *    0.2:    Checks for 'gzip' in the Accept-Encoding header
     *    0.1:    First working version.
     *
     * Thanks To (Suggestions and stuff):
     *    ?@boas.anthro.mnsu.edu    http://php.net/manual/function.gzcompress.php
     *    Kaoslord        <kaoslord@chaos-productions.com>
     *    Michael R. Gile        <gilem@wsg.net>
     *    Christian Hamm        <chh@admaster.de>
     *    Anil Madhavapeddy    <anil@recoil.org>
     *
     * The most recent version is available at:
     *    http://Leknor.com/code/
     *
     */

    var $_version = 0.67; // Version of the gzip_encode class

    var $level;        // Compression level
    var $encoding;    // Encoding type
    var $crc;        // crc of the output
    var $size;        // size of the uncompressed content
    var $gzsize;    // size of the compressed content

    /*
     * gzip_encode constructor - gzip encodes the current output buffer
     * if the browser supports it.
     *
     * Note: all arguments are optionial.
     *
     * You can specify one of the following for the first argument:
     *    0:    No compression
     *    1:    Min compression
     *    ...    Some compression (integer from 1 to 9)
     *    9:    Max compression
     *    true:    Determin the compression level from the system load. The
     *        higher the load the less the compression.
     *
     * You can specify one of the following for the second argument:
     *    true:    Don't actully output the compressed form but run as if it
     *        had. Used for debugging.
     */
    function gzip_encode($level = 9, $debug = false) {
    global $HTTP_ACCEPT_ENCODING;
    if (!function_exists('gzcompress')) {
        trigger_error('gzcompress not found, ' .
            'zlib needs to be installed for gzip_encode',
            E_USER_WARNING);
        return;
    }
    if (!function_exists('crc32')) {
        trigger_error('crc32() not found, ' .
            'PHP >= 4.0.1 needed for gzip_encode', E_USER_WARNING);
        return;
    }
    if (headers_sent()) return;
    if (connection_status() !== 0) return;
    $encoding = $this->gzip_accepted();
    if (!$encoding) return;
    $this->encoding = $encoding;

    if ($level === true) {
        $level = $this->get_complevel();
    }
    $this->level = $level;

    $contents = ob_get_contents();
    if ($contents === false) return;

    $gzdata = "\x1f\x8b\x08\x00\x00\x00\x00\x00"; // gzip header
    $size = strlen($contents);
    $crc = crc32($contents);
    $gzdata .= gzcompress($contents, $level);
    $gzdata = substr($gzdata, 0, strlen($gzdata) - 4); // fix crc bug
    $gzdata .= pack("V",$crc) . pack("V", $size);

    $this->size = $size;
    $this->crc = $crc;
    $this->gzsize = strlen($gzdata);

    if ($debug) {
        return;
    }

    ob_end_clean();
    Header('Content-Encoding: ' . $encoding);
    Header('Vary: Accept-Encoding');
    Header('Content-Length: ' . strlen($gzdata));
    Header('X-Content-Encoded-By: class.gzip_encode '.$this->_version);

    echo $gzdata;
    }
   

    /*
     * gzip_accepted() - Test headers for Accept-Encoding: gzip
     *
     * Returns: if proper headers aren't found: false
     *          if proper headers are found: 'gzip' or 'x-gzip'
     *
     * Tip: using this function you can test if the class will gzip the output
     *  without actually compressing it yet, eg:
     *    if (gzip_encode::gzip_accepted()) {
     *       echo "Page will be gziped";
     *    }
     *  note the double colon syntax, I don't know where it is documented but
     *  somehow it got in my brain.
     */
    function gzip_accepted() {
    global $HTTP_ACCEPT_ENCODING;
    if (strpos($HTTP_ACCEPT_ENCODING, 'gzip') === false) return false;
    if (strpos($HTTP_ACCEPT_ENCODING, 'x-gzip') === false) {
        $encoding = 'gzip';
    } else {
        $encoding = 'x-gzip';
    }

    // Test file type. I wish I could get HTTP response headers.
    $magic = substr(ob_get_contents(),0,4);
    if (substr($magic,0,2) === '^_') {
        // gzip data
        $encoding = false;
    } else if (substr($magic,0,3) === 'GIF') {
        // gif images
        $encoding = false;
    } else if (substr($magic,0,2) === "\xFF\xD8") {
        // jpeg images
        $encoding = false;
    } else if (substr($magic,0,4) === "\x89PNG") {
        // png images
        $encoding = false;
    } else if (substr($magic,0,3) === 'FWS') {
        // Don't gzip Shockwave Flash files. Flash on windows incorrectly
        // claims it accepts gzip'd content.
        $encoding = false;
    } else if (substr($magic,0,2) === 'PK') {
        // pk zip file
        $encoding = false;
    }

    return $encoding;
    }

    /*
     * get_complevel() - The level of compression we should use.
     *
     * Returns an int between 0 and 9 inclusive.
     *
     * Tip: $gzleve = gzip_encode::get_complevel(); to get the compression level
     *      that will be used with out actually compressing the output.
     *
     * Help: if you use an OS other then linux please send me code to make
     * this work with your OS - Thanks
     */
    function get_complevel() {
    $uname = posix_uname();
    switch ($uname['sysname']) {
        case 'Linux':
        $cl = (1 - $this->linux_loadavg()) * 10;
        $level = (int)max(min(9, $cl), 0);
        break;
        case 'FreeBSD':
        $cl = (1 - $this->freebsd_loadavg()) * 10;
        $level = (int)max(min(9, $cl), 0);
        break;
        default:
        $level = 3;
        break;
    }
    return $level;
    }

    /*
     * linux_loadavg() - Gets the max() system load average from /proc/loadavg
     *
     * The max() Load Average will be returned
     */
    function linux_loadavg() {
    $buffer = "0 0 0";
    $f = fopen("/proc/loadavg","r");
    if (!feof($f)) {
        $buffer = fgets($f, 1024);
    }
    fclose($f);
    $load = explode(" ",$buffer);
    return max((float)$load[0], (float)$load[1], (float)$load[2]);
    }

    /*
     * freebsd_loadavg() - Gets the max() system load average from uname(1)
     *
     * The max() Load Average will be returned
     *
     * I've been told the code below will work on solaris too, anyone wanna
     * test it?
     */
    function freebsd_loadavg() {
    $buffer= `uptime`;
    ereg("averag(es|e): ([0-9][.][0-9][0-9]), ([0-9][.][0-9][0-9]), ([0-9][.][0-9][0-9]*)", $buffer, $load);

    return max((float)$load[2], (float)$load[3], (float)$load[4]);
    } 
}

?>

Open in new window

karoldvlCommented:
I've tested this class using the following snippet, and it seems to be working fine.

Do you have something in place which could interfere with gzip_encode class (headers sent on the way, output buffering changes in the script)?
<?php
ob_start();
include('class.gzip_encode.php');
?>
Compression test
<?php
new gzip_encode();
?>

Open in new window

Rowby Goren Makes an Impact on Screen and Online

Learn about longtime user Rowby Goren and his great contributions to the site. We explore his method for posing questions that are likely to yield a solution, and take a look at how his career transformed from a Hollywood writer to a website entrepreneur.

Dean OBrienAuthor Commented:
Hi Karoldvl

Thanks for getting back to me.
I dont think there is anything getting in the way (please see my index.php attached).
Is there some server setting which could be overriding this? Im pretty sure it is not working at the moment because when i check www.mygolfbook.co.uk/index.php using live headers (firefox), it states the served compression type as being 'chunked'. Does that mean it is not working? Are you able to test the link?

Regards
Easynow
<?php
ob_start();
include('class.gzip_encode.php');
session_start();
require_once('CodeBlocks/database_connection.php');
require_once('CodeBlocks/check_task.php');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My Golf Book - The Social Golf Networf</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="My Golf Book Virtual Golf Network Societies Tournament" />
<meta name="description" content="MyGolfBook Home Page - The social Golf Network" />
<?php if($Res=='High') { ?>
<link rel="stylesheet" title="Default" href="mygolfbookstyle.css" type="text/css" />
<?php } else { ?>
<link rel="stylesheet" title="Default" href="mygolfbookstyle_low.css" type="text/css" />
<?php } ?>
<link rel="shortcut icon" href="londonsash.ico" />
</head>
<body>
<div id="container">
	<div id="Banner"><img src="images/header.jpg" style="border:0;width:980px;height:100px;" alt="My Golf Book - The Social Golf Network" /></div>
<?php include 'mainmenu.php'; ?>
 	<div id="Content" class="mainpage">
		<div id="info-window-main-page" class="lightblue85">
			<h2 class="homepage-title">What is My Golf Book?</h2>
			<div id="info-window-main-page-sub">
			<p>MyGolfbook is a network of virtual golf societies across the country, where each society is open to anyone who lives close enough to attend games regularly. Once a member you can host customised games or tournaments and track peoples progress through the site.</p>
			<p>This is an ideal opportunity to play golf with new people in your area and also provides an opportunity for beginners to play in competitions they might not normally have been invited to join. </p>
			<p style="text-align:center"><a href="memberslounge.php?Task=AddMember&amp;LocationID=0"><img src="images/three-step-medium.jpg" style="border:0px;margin:0px;width:315px;height:130px" alt="Three steps to joining my golf book" /></a></p>
			</div>
		</div>
	<div id="FB">
		<script type="text/javascript" src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/en_GB"></script>
		<script type="text/javascript">FB.init("057f54532f95082286a5783014afd913");</script>
		<div id="FBin"></div>
	</div>
	</div>
<?php require_once('core_elements/footer.php'); ?>
<?php require_once('CodeBlocks/logincheck.php'); ?>
</div>
<script type="text/javascript">/* <![CDATA[ */ var divX = document.getElementById('FBin').innerHTML="<fb:fan profile_id='23250669223' stream='' connections='20' width='290' height='430'></fb:fan>"; /* ]]> */</script>
<?php include_once("analyticstracking.php") ?>
</body>
</html>
<?php
new gzip_encode();
?>

Open in new window

karoldvlCommented:
Sorry, I missed the response in a bunch of other questions.

Testing your site it does look there's no compression in the content served.

Try creating a blank page without any other includes like the one posted earlier:
<?php
ob_start();
include('class.gzip_encode.php');
?>
Compression test
<?php
new gzip_encode();
?>

and see if it also has problems. If so, then it's probably, as you said, some server config problem.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Dean OBrienAuthor Commented:
sorry for delay, thanks for help
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.