Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP Manual GZip Encoding

I was testing my website with Page Speed and the result was around 70/100. Enable Compression was the first and most important factor in slowing it down.

I know that I can do that by modifying the php.ini to automatically do that but I was more interested in the manual method (gzencode).

The problem is either all browsers fail in opening the website (Firefox: "The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.", Chrome: "303, ERR Content Encoding", etc.) or they display the encoded string.

Live Headers shows that the browser accepts the encoding, and the response has the content type set, but it still fails.

GET / HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 5827
Vary: Accept-Encoding

private function _compress($data) {
    //return trim(preg_replace(array('/\>[^\S ]+/s','/[^\S ]+\</s','/(\s)+/s'), array('>','<','\\1'), $data));
    $supportsGzip = strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;

    ob_start();
    if ($supportsGzip) {
        echo gzencode(trim(preg_replace('/\s+/', ' ', $data)), 9);
    } else {
        echo $data;
    }

    $content = ob_get_contents();
    header("content-type: text/html; charset: UTF-8");
    header("cache-control: must-revalidate");
    $offset = 60 * 60;
    $expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
    header($expire);
    header('Content-Length: ' . strlen($content));
    header('Vary: Accept-Encoding');
    ob_end_clean();
    echo $content;
}

If I change the Content-Encoding to zlib, I get the encoded string:

‹������ÕZÿsÛ¶ÿW^‘¥²o‘¨/–-Ë–Ú؉_Ôµ•õÚ_v I°I‚!A©j–Öºnçÿb·»%ÍÚë²nëå?‘þ›=€¤L)’,ÛIw>ŸEâxïáƒ÷°ùÞ½O¶Ÿï߇Žtlؼµ·» $kŸ•¶ ã^ã<܃•\¾� Ÿº—\¸Ô6ŒûŽ”^Õ0z½^®WÊ ¿m4ÅjÅ°…XÎ’©Ã¦ænS·]#ÌÕF-|8LRPL²ìIÈ»5²-\É\™mô=FÀŒJ5"Ù—RóÝ�³Cý€ÉZ([ÙŠb%¹´YýÑãáîcx}±iD´˜¿KV#4”á§x>¬°à®íÒ ãpÅËæî1øÌ®‘@öm

I don’t really care anymore about getting the compression as much as I want to know why its not working.

Cheers,

like image 386
M.Alnashmi Avatar asked Apr 18 '11 05:04

M.Alnashmi


2 Answers

Well, I think it's because you're trying to compress an empty string.

I took your script as you gave it, and ran it in FF and IE.

Both failed, and FF said that there was an issue (like you described).

However, I then noticed $data is an empty string.

When I set $data = "Some test data."; at the top of the file it worked immediately (browser displayed "Some test data."), and checking in Firebug, I can see the correct headers.

Content-Encoding    gzip
Content-Length  68
Vary    Accept-Encoding
Content-Type    text/html

Edit: Also, just to point out, your if ($supportsGzip) { is a bit odd, because your else condition should actually echo out $data, not $content.

Edit: Okay, based on your revised function above, there are two key problems.

The primary problem has to do with the fact that you're wiping out your headers by calling ob_end_clean(). A comment on the PHP Docs states that "ob_end_clean() does discard headers".

This means any headers you set before calling ob_end_clean() will get wiped. Also, your revised function doesn't send a gzip encoding header, either.

I must say that there is probably no need to even use ob_start and related functions here, either. Try the following:

function _compress( $data ) {

    $supportsGzip = strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) !== false;


    if ( $supportsGzip ) {
        $content = gzencode( trim( preg_replace( '/\s+/', ' ', $data ) ), 9);
        header('Content-Encoding: gzip');
    } else {
        $content = $data;
    }

    $offset = 60 * 60;
    $expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";

    header("content-type: text/html; charset: UTF-8");
    header("cache-control: must-revalidate");
    header( $expire );
    header( 'Content-Length: ' . strlen( $content ) );
    header('Vary: Accept-Encoding');

    echo $content;

}

_compress( "Some test data" );

This works in IE and FF, but I didn't have time to test other browsers.

If you really must use ob_start and related functions, make sure you set your headers after you call ob_end_clean().

like image 167
Craig Sefton Avatar answered Nov 01 '22 22:11

Craig Sefton


I'd suggest to use http://php.net/manual/de/function.ob-gzhandler.php, this works out of the box for me:

In my index.php I just place this before some output:

    /**
     * Enable GZIP-Compression for Browser that support it.
     */
    ob_start("ob_gzhandler");

And it encodes it!

like image 20
daschl Avatar answered Nov 01 '22 23:11

daschl