1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
|
<?php
/**
* News: I had once said that when PHP 4.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. PHP 4.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 be better for some sites:
* http://www.remotecommunications.com/apache/mod_gzip/
* I've read that the above doesn't work with PHP output.
*
* Changes compared to the upstream version:
*
* 2005-12-09 Peter Niederlag <peter@niederlag.de>
* - Fixed bug #1976: PHP5 type-conversion of string 'true' and boolean
*
* $Id: class.gzip_encode.php 1421 2006-04-10 09:27:15Z mundaun $
*
* @author Sandy McArthur, Jr. <leknor@leknor.com>
*/
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.
* One very slight modification 2005 for PHP5 compatibility reasons for TYPO3 port by Peter Niederlag
*
* 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.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>
*
* The most recent version is available at:
* http://Leknor.com/code/
*
*/
var $_version = 0.66; // 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 = 3, $debug = false, $outputCompressedSizes=0) {
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 (strtolower($level) == 'true' || $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
// By Kasper Skaarhoj, start
if ($outputCompressedSizes) {
$contents.=chr(10)."<!-- Compressed, level ".$level.", original size was ".strlen($contents)." bytes. New size is ".strlen(gzcompress($contents, $level))." bytes -->";
$size = strlen($contents); // Must set again!
}
// By Kasper Skaarhoj, end
$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('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() {
if (strpos(getenv("HTTP_ACCEPT_ENCODING"), 'gzip') === false) return false;
if (strpos(getenv("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","rb");
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`;
$load = array();
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]);
}
}
?>
|