class.gzip_encode.php

Go to the documentation of this file.
00001 <?php
00002 /**
00003  * News: I had once said that when PHP 4.0.5 comes out I will reccomend the built in
00004  * ob_gzhandler over my code unless you are generating flash or images on the fly.
00005  *
00006  * I was wrong. PHP 4.0.5 is out and ob_gzhandler doesn't work for me.
00007  *
00008  * Note: This is rather cool: http://leknor.com/code/gziped.php
00009  * It will calculate the effects of this class on a page.
00010  * compression level, cpu time, download time, etc
00011  *
00012  * Note: this may be better for some sites:
00013  * http://www.remotecommunications.com/apache/mod_gzip/
00014  * I've read that the above doesn't work with PHP output.
00015  *
00016  * Changes compared to the upstream version:
00017  *
00018  * 2007-03-27  Oliver Hader  <oh@inpublica.de>
00019  *  - Fixed bug #4623: Content encoding with x-gzip not allowed
00020  *  - Fixed missing comments and line formats (cleaner)
00021  * 2005-12-09  Peter Niederlag  <peter@niederlag.de>
00022  *  - Fixed bug #1976: PHP5 type-conversion of string 'true' and boolean
00023  *
00024  * $Id: class.gzip_encode.php 7307 2010-04-12 16:17:20Z benni $
00025  *
00026  * @author  Sandy McArthur, Jr. <leknor@leknor.com>
00027  * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.5, we're using the "ob_gzhandler" for compression now.
00028  */
00029 /**
00030  * [CLASS/FUNCTION INDEX of SCRIPT]
00031  *
00032  *
00033  *
00034  *   53: class gzip_encode
00035  *  193:     function gzip_encode($level = 3, $debug=false, $outputCompressedSizes=false)
00036  *  268:     function gzip_accepted()
00037  *  317:     function get_complevel()
00038  *  342:     function linux_loadavg()
00039  *  363:     function freebsd_loadavg()
00040  *
00041  * TOTAL FUNCTIONS: 5
00042  * (This index is automatically created/updated by the extension "extdeveval")
00043  *
00044  */
00045 
00046 
00047 
00048 /**
00049  * gzip_encode - a class to gzip encode php output
00050  *
00051  * @author      Sandy McArthur, Jr. <Leknor@Leknor.com>
00052  * @package     TYPO3
00053  * @subpackage  t3lib
00054  */
00055 class gzip_encode {
00056     /**
00057      * gzip_encode - a class to gzip encode php output
00058      *
00059      * By Sandy McArthur, Jr. <Leknor@Leknor.com>
00060      *
00061      * Copyright 2001 (c) All Rights Reserved, All Responsibility Yours.
00062      * One very slight modification 2005 for PHP5 compatibility reasons for TYPO3 port by Peter Niederlag
00063      *
00064      * This code is released under the GNU LGPL Go read it over here:
00065      * http://www.gnu.org/copyleft/lesser.html
00066      *
00067      * I do make one optional request, I would like an account on or a
00068      * copy of where this code is used. If that is not possible then
00069      * an email would be cool.
00070      *
00071      * How to use:
00072      * 1. Output buffering has to be turned on. You can do this with ob_start()
00073      *    <http://php.net/manual/function.ob-start.php> or in the php config
00074      *    file. Nothing bad happens if output buffering isn't turned on, your
00075      *    page just won't get compressed.
00076      * 2. Include the class file.
00077      * 3. At the _very_ end of your script create an instance of the encode
00078      *    class.
00079      *
00080      * eg:
00081      *  ------------Start of file----------
00082      *  |<?php
00083      *  | ob_start();
00084      *  | include('class.gzip_encode.php');
00085      *  |?>
00086      *  |<HTML>
00087      *  |... the page ...
00088      *  |</HTML>
00089      *  |<?php
00090      *  | new gzip_encode();
00091      *  |?>
00092      *  -------------End of file-----------
00093      *
00094      * Things to note:
00095      * 1. There is no space before the beginning of the file and the '<?php ' tag
00096      * 2. The ob_start() line is optional if output buffering is turned on in
00097      *    the main config file.
00098      * 3. Turning on and off output buffering just won't work.
00099      * 4. There must be nothing after the last '?>' tag at the end of the file.
00100      *    Be careful of a space hiding there.
00101      * 5. There are better ways to compress served content but I think this is
00102      *    the only way to compress php output.
00103      * 6. Your auto_prepend_file is a good place for the ob_start() and
00104      *    your auto_append_file is a good place for new gzip_encode().
00105      * 7. If you put new gzip_encode() in your auto.append file then you can
00106      *    call ob_end_flush() in your script to disable compression.
00107      *
00108      * This was written from scratch from info freely available on the web.
00109      *
00110      * These site(s) were useful to me:
00111      *  http://www.php.net/manual/
00112      *  http://www.ietf.org/rfc/rfc2616.txt (Sections: 3.5, 14.3, 14.11)
00113      *
00114      * Requirments:
00115      *  PHP 4.0.1+: I use the '===' operator, and output buffering, crc32();
00116      *  zlib:       Needed for the gzip encoding. (Odds are you have it)
00117      *
00118      * Benchmarks:
00119      *  Take a look at http://Leknor.com/code/gziped.php and feed it a page to
00120      *  get an idea of how it will preform on your data or page.
00121      *
00122      * To Do:
00123      * 1. I have reports of no content errors. I can't seem to duplicate this.
00124      *    Please visit my discussion boards if you think you may be able to help
00125      * 2. The Accept-Encoding isn't handled to spec. Check out 14.3 in RFC 2616
00126      *    to see how it should be done.
00127      *
00128      * Change Log:
00129      *  0.66:   Big bug fix. It wouldn't compress when it should.
00130      *  0.65:   Fix for PHP-4.0.5 suddenly removing the connection_timeout() function.
00131      *  0.62:   Fixed a typo
00132      *  0.61:   Detect file types more like described in the magic number files, also
00133      *      added detection for gzip and pk zip files.
00134      *  0.6:    Detect common file types that shouldn't be compressed, mainly
00135      *      for images and swf (Shockwave Flash doesn't really accept gzip)
00136      *  0.53:   Made gzip_accepted() method so everyone can detect if a page
00137      *      will be gzip'ed with ease.
00138      *  0.52:   Detection and graceful handling of improper install/missing libs
00139      *  0.51:   Added FreeBSD load average detection.
00140      *  0.5:    Passing true as the first parameter will try to calculate the
00141      *      compression level from the server's load average. Passing true
00142      *      as the second parameter will turn on debugging.
00143      *  0.4:    No longer uses a temp file to compress the output. Should speed
00144      *      thing up a bit and reduce wear on your hard disk. Also test if
00145      *      the http headers have been sent.
00146      *  0.31:   Made a small change to the tempnam() line to hopefully be more
00147      *      portable.
00148      *  0.3:    Added code for the 'x-gzip'. This is untested, I don't know of
00149      *      any browser that uses it but the RFC said to look out for it.
00150      *  0.2:    Checks for 'gzip' in the Accept-Encoding header
00151      *  0.1:    First working version.
00152      *
00153      * Thanks To (Suggestions and stuff):
00154      *  ?@boas.anthro.mnsu.edu  http://php.net/manual/function.gzcompress.php
00155      *  Kaoslord        <kaoslord@chaos-productions.com>
00156      *  Michael R. Gile     <gilem@wsg.net>
00157      *  Christian Hamm      <chh@admaster.de>
00158      *
00159      * The most recent version is available at:
00160      *  http://Leknor.com/code/
00161      *
00162      */
00163 
00164     var $_version = 0.66; // Version of the gzip_encode class
00165 
00166     var $level;     // Compression level
00167     var $encoding;  // Encoding type
00168     var $crc;       // crc of the output
00169     var $size;      // size of the uncompressed content
00170     var $gzsize;    // size of the compressed content
00171 
00172     /**
00173      * gzip_encode constructor - gzip encodes the current output buffer
00174      * if the browser supports it.
00175      *
00176      * Note: all arguments are optionial.
00177      *
00178      * You can specify one of the following for the first argument:
00179      *  0:  No compression
00180      *  1:  Min compression
00181      *  ... Some compression (integer from 1 to 9)
00182      *  9:  Max compression
00183      *  true:   Determin the compression level from the system load. The
00184      *      higher the load the less the compression.
00185      *
00186      * You can specify one of the following for the second argument:
00187      *  true:   Don't actully output the compressed form but run as if it
00188      *      had. Used for debugging.
00189      *
00190      * @param   integer     $level: Define the level of compression between 0 (none) and 9 (best compression)
00191      * @param   boolean     $debug: If true, no data will be outputted (default: false)
00192      * @param   boolean     $outputCompressedSizes: If true, the original and compressed size appended as HTML (default: false)
00193      * @return  void
00194      * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.5, we're using the "ob_gzhandler" for compression now.
00195      */
00196     function gzip_encode($level=3, $debug=false, $outputCompressedSizes=false) {
00197         t3lib_div::logDeprecatedFunction();
00198 
00199         if (!function_exists('gzcompress')) {
00200             trigger_error('gzcompress not found, ' .
00201                 'zlib needs to be installed for gzip_encode',
00202                 E_USER_WARNING);
00203             return;
00204         }
00205         if (!function_exists('crc32')) {
00206             trigger_error('crc32() not found, ' .
00207                 'PHP >= 4.0.1 needed for gzip_encode', E_USER_WARNING);
00208             return;
00209         }
00210         if (headers_sent()) return;
00211         if (connection_status() !== 0) return;
00212         $encoding = $this->gzip_accepted();
00213         if (!$encoding) return;
00214         $this->encoding = $encoding;
00215 
00216         if (strtolower($level) == 'true' || $level === true) {
00217             $level = $this->get_complevel();
00218         }
00219         $this->level = $level;
00220 
00221         $contents = ob_get_contents();
00222         if ($contents === false) return;
00223 
00224         $gzdata = "\x1f\x8b\x08\x00\x00\x00\x00\x00"; // gzip header
00225 
00226             // By Kasper Skaarhoj, start
00227         if ($outputCompressedSizes) {
00228             $contents.=LF."<!-- Compressed, level ".$level.", original size was ".strlen($contents)." bytes. New size is ".strlen(gzcompress($contents, $level))." bytes -->";
00229             $size = strlen($contents);  // Must set again!
00230         }
00231             // By Kasper Skaarhoj, end
00232 
00233         $size = strlen($contents);
00234         $crc = crc32($contents);
00235         $gzdata .= gzcompress($contents, $level);
00236         $gzdata = substr($gzdata, 0, strlen($gzdata) - 4); // fix crc bug
00237         $gzdata .= pack("V",$crc) . pack("V", $size);
00238 
00239         $this->size = $size;
00240         $this->crc = $crc;
00241         $this->gzsize = strlen($gzdata);
00242 
00243         if ($debug) {
00244             return;
00245         }
00246 
00247         ob_end_clean();
00248         Header('Content-Encoding: ' . $encoding);
00249         Header('Content-Length: ' . strlen($gzdata));
00250         Header('X-Content-Encoded-By: class.gzip_encode '.$this->_version);
00251 
00252         echo $gzdata;
00253     }
00254 
00255 
00256     /**
00257      * gzip_accepted() - Test headers for Accept-Encoding: gzip
00258      * Returns: if proper headers aren't found: false
00259      *          if proper headers are found: 'gzip' or 'x-gzip'
00260      *
00261      * Tip: using this function you can test if the class will gzip the output
00262      *  without actually compressing it yet, eg:
00263      *    if (gzip_encode::gzip_accepted()) {
00264      *       echo "Page will be gziped";
00265      *    }
00266      *  note the double colon syntax, I don't know where it is documented but
00267      *  somehow it got in my brain.
00268      *
00269      * @return  mixed       Returns 'gzip' if the client browser accepts gzip encoding, otherwise false
00270      * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.5, we're using the "ob_gzhandler" for compression now.
00271      */
00272     function gzip_accepted() {
00273         t3lib_div::logDeprecatedFunction();
00274 
00275             // Checks, if the accepted encoding supports gzip or x-gzip.
00276             // Furthermore a qvalue check is done. "gzip;q=0" means no gzip accepted at all.
00277         $acceptEncoding = t3lib_div::getIndpEnv('HTTP_ACCEPT_ENCODING');
00278         if (preg_match('/(^|,\s*)(x-)?gzip(;q=(\d(\.\d+)?))?(,|$)/i', $acceptEncoding, $match) && ($match[4] === '' || $match[4] > 0)) {
00279             $encoding = 'gzip';
00280         } else {
00281             return false;
00282         }
00283 
00284             // Test file type. I wish I could get HTTP response headers.
00285         $magic = substr(ob_get_contents(),0,4);
00286         if (substr($magic,0,2) === '^_') {
00287             // gzip data
00288             $encoding = false;
00289         } else if (substr($magic,0,3) === 'GIF') {
00290             // gif images
00291             $encoding = false;
00292         } else if (substr($magic,0,2) === "\xFF\xD8") {
00293             // jpeg images
00294             $encoding = false;
00295         } else if (substr($magic,0,4) === "\x89PNG") {
00296             // png images
00297             $encoding = false;
00298         } else if (substr($magic,0,3) === 'FWS') {
00299             // Don't gzip Shockwave Flash files. Flash on windows incorrectly
00300             // claims it accepts gzip'd content.
00301             $encoding = false;
00302         } else if (substr($magic,0,2) === 'PK') {
00303             // pk zip file
00304             $encoding = false;
00305         }
00306 
00307         return $encoding;
00308     }
00309 
00310     /**
00311      * get_complevel() - The level of compression we should use.
00312      *
00313      * Returns an int between 0 and 9 inclusive.
00314      *
00315      * Tip: $gzleve = gzip_encode::get_complevel(); to get the compression level
00316      *      that will be used with out actually compressing the output.
00317      *
00318      * Help: if you use an OS other then linux please send me code to make
00319      * this work with your OS - Thanks
00320      *
00321      * @return  integer     Suggests a level of compression (0..9) for the current situation
00322      * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.5, we're using the "ob_gzhandler" for compression now.
00323      */
00324     function get_complevel() {
00325         t3lib_div::logDeprecatedFunction();
00326 
00327         $uname = posix_uname();
00328         switch ($uname['sysname']) {
00329             case 'Linux':
00330                 $cl = (1 - $this->linux_loadavg()) * 10;
00331                 $level = (int)max(min(9, $cl), 0);
00332             break;
00333             case 'FreeBSD':
00334                 $cl = (1 - $this->freebsd_loadavg()) * 10;
00335                 $level = (int)max(min(9, $cl), 0);
00336                 break;
00337                 default:
00338                 $level = 3;
00339             break;
00340         }
00341         return $level;
00342     }
00343 
00344     /**
00345      * linux_loadavg() - Gets the max() system load average from /proc/loadavg
00346      *
00347      * The max() Load Average will be returned
00348      *
00349      * @return  float       Returns the current load average
00350      * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.5, we're using the "ob_gzhandler" for compression now.
00351      */
00352     function linux_loadavg() {
00353         t3lib_div::logDeprecatedFunction();
00354 
00355         $buffer = '0 0 0';
00356         $f = @fopen('/proc/loadavg', 'rb');
00357         if ($f) {
00358             if (!feof($f)) {
00359                 $buffer = fgets($f, 1024);
00360             }
00361             fclose($f);
00362         }
00363         $load = explode(' ', $buffer);
00364         return max((float)$load[0], (float)$load[1], (float)$load[2]);
00365     }
00366 
00367     /**
00368      * freebsd_loadavg() - Gets the max() system load average from uname(1)
00369      *
00370      * The max() Load Average will be returned
00371      *
00372      * I've been told the code below will work on solaris too, anyone wanna
00373      * test it?
00374      *
00375      * @return  float       Returns the current load average
00376      * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.5, we're using the "ob_gzhandler" for compression now.
00377      */
00378     function freebsd_loadavg() {
00379         t3lib_div::logDeprecatedFunction();
00380 
00381         $buffer= `uptime`;
00382         $load = array();
00383         preg_match('/averag(es|e): ([0-9][.][0-9][0-9]), ([0-9][.][0-9][0-9]), ([0-9][.][0-9][0-9]*)/', $buffer, $load);
00384 
00385         return max((float)$load[2], (float)$load[3], (float)$load[4]);
00386     }
00387 }
00388 
00389 ?>

Generated on Sat Jul 24 04:17:16 2010 for TYPO3 API by  doxygen 1.4.7