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