Fixed bug #14050: CleanUp - CGL format of t3lib files - t3lib_tceforms_inline
[Packages/TYPO3.CMS.git] / t3lib / class.gzip_encode.php
1 <?php
2 /**
3 * News: I had once said that when PHP 4.0.5 comes out I will reccomend the built in
4 * ob_gzhandler over my code unless you are generating flash or images on the fly.
5 *
6 * I was wrong. PHP 4.0.5 is out and ob_gzhandler doesn't work for me.
7 *
8 * Note: This is rather cool: http://leknor.com/code/gziped.php
9 * It will calculate the effects of this class on a page.
10 * compression level, cpu time, download time, etc
11 *
12 * Note: this may be better for some sites:
13 * http://www.remotecommunications.com/apache/mod_gzip/
14 * I've read that the above doesn't work with PHP output.
15 *
16 * Changes compared to the upstream version:
17 *
18 * 2007-03-27 Oliver Hader <oh@inpublica.de>
19 * - Fixed bug #4623: Content encoding with x-gzip not allowed
20 * - Fixed missing comments and line formats (cleaner)
21 * 2005-12-09 Peter Niederlag <peter@niederlag.de>
22 * - Fixed bug #1976: PHP5 type-conversion of string 'true' and boolean
23 *
24 * $Id$
25 *
26 * @author Sandy McArthur, Jr. <leknor@leknor.com>
27 * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.5, we're using the "ob_gzhandler" for compression now.
28 */
29 /**
30 * [CLASS/FUNCTION INDEX of SCRIPT]
31 *
32 *
33 *
34 * 53: class gzip_encode
35 * 193: function gzip_encode($level = 3, $debug=false, $outputCompressedSizes=false)
36 * 268: function gzip_accepted()
37 * 317: function get_complevel()
38 * 342: function linux_loadavg()
39 * 363: function freebsd_loadavg()
40 *
41 * TOTAL FUNCTIONS: 5
42 * (This index is automatically created/updated by the extension "extdeveval")
43 *
44 */
45
46
47 /**
48 * gzip_encode - a class to gzip encode php output
49 *
50 * @author Sandy McArthur, Jr. <Leknor@Leknor.com>
51 * @package TYPO3
52 * @subpackage t3lib
53 */
54 class gzip_encode {
55 /**
56 * gzip_encode - a class to gzip encode php output
57 *
58 * By Sandy McArthur, Jr. <Leknor@Leknor.com>
59 *
60 * Copyright 2001 (c) All Rights Reserved, All Responsibility Yours.
61 * One very slight modification 2005 for PHP5 compatibility reasons for TYPO3 port by Peter Niederlag
62 *
63 * This code is released under the GNU LGPL Go read it over here:
64 * http://www.gnu.org/copyleft/lesser.html
65 *
66 * I do make one optional request, I would like an account on or a
67 * copy of where this code is used. If that is not possible then
68 * an email would be cool.
69 *
70 * How to use:
71 * 1. Output buffering has to be turned on. You can do this with ob_start()
72 * <http://php.net/manual/function.ob-start.php> or in the php config
73 * file. Nothing bad happens if output buffering isn't turned on, your
74 * page just won't get compressed.
75 * 2. Include the class file.
76 * 3. At the _very_ end of your script create an instance of the encode
77 * class.
78 *
79 * eg:
80 * ------------Start of file----------
81 * |<?php
82 * | ob_start();
83 * | include('class.gzip_encode.php');
84 * |?>
85 * |<HTML>
86 * |... the page ...
87 * |</HTML>
88 * |<?php
89 * | new gzip_encode();
90 * |?>
91 * -------------End of file-----------
92 *
93 * Things to note:
94 * 1. There is no space before the beginning of the file and the '<?php ' tag
95 * 2. The ob_start() line is optional if output buffering is turned on in
96 * the main config file.
97 * 3. Turning on and off output buffering just won't work.
98 * 4. There must be nothing after the last '?>' tag at the end of the file.
99 * Be careful of a space hiding there.
100 * 5. There are better ways to compress served content but I think this is
101 * the only way to compress php output.
102 * 6. Your auto_prepend_file is a good place for the ob_start() and
103 * your auto_append_file is a good place for new gzip_encode().
104 * 7. If you put new gzip_encode() in your auto.append file then you can
105 * call ob_end_flush() in your script to disable compression.
106 *
107 * This was written from scratch from info freely available on the web.
108 *
109 * These site(s) were useful to me:
110 * http://www.php.net/manual/
111 * http://www.ietf.org/rfc/rfc2616.txt (Sections: 3.5, 14.3, 14.11)
112 *
113 * Requirments:
114 * PHP 4.0.1+: I use the '===' operator, and output buffering, crc32();
115 * zlib: Needed for the gzip encoding. (Odds are you have it)
116 *
117 * Benchmarks:
118 * Take a look at http://Leknor.com/code/gziped.php and feed it a page to
119 * get an idea of how it will preform on your data or page.
120 *
121 * To Do:
122 * 1. I have reports of no content errors. I can't seem to duplicate this.
123 * Please visit my discussion boards if you think you may be able to help
124 * 2. The Accept-Encoding isn't handled to spec. Check out 14.3 in RFC 2616
125 * to see how it should be done.
126 *
127 * Change Log:
128 * 0.66: Big bug fix. It wouldn't compress when it should.
129 * 0.65: Fix for PHP-4.0.5 suddenly removing the connection_timeout() function.
130 * 0.62: Fixed a typo
131 * 0.61: Detect file types more like described in the magic number files, also
132 * added detection for gzip and pk zip files.
133 * 0.6: Detect common file types that shouldn't be compressed, mainly
134 * for images and swf (Shockwave Flash doesn't really accept gzip)
135 * 0.53: Made gzip_accepted() method so everyone can detect if a page
136 * will be gzip'ed with ease.
137 * 0.52: Detection and graceful handling of improper install/missing libs
138 * 0.51: Added FreeBSD load average detection.
139 * 0.5: Passing true as the first parameter will try to calculate the
140 * compression level from the server's load average. Passing true
141 * as the second parameter will turn on debugging.
142 * 0.4: No longer uses a temp file to compress the output. Should speed
143 * thing up a bit and reduce wear on your hard disk. Also test if
144 * the http headers have been sent.
145 * 0.31: Made a small change to the tempnam() line to hopefully be more
146 * portable.
147 * 0.3: Added code for the 'x-gzip'. This is untested, I don't know of
148 * any browser that uses it but the RFC said to look out for it.
149 * 0.2: Checks for 'gzip' in the Accept-Encoding header
150 * 0.1: First working version.
151 *
152 * Thanks To (Suggestions and stuff):
153 * ?@boas.anthro.mnsu.edu http://php.net/manual/function.gzcompress.php
154 * Kaoslord <kaoslord@chaos-productions.com>
155 * Michael R. Gile <gilem@wsg.net>
156 * Christian Hamm <chh@admaster.de>
157 *
158 * The most recent version is available at:
159 * http://Leknor.com/code/
160 *
161 */
162
163 var $_version = 0.66; // Version of the gzip_encode class
164
165 var $level; // Compression level
166 var $encoding; // Encoding type
167 var $crc; // crc of the output
168 var $size; // size of the uncompressed content
169 var $gzsize; // size of the compressed content
170
171 /**
172 * gzip_encode constructor - gzip encodes the current output buffer
173 * if the browser supports it.
174 *
175 * Note: all arguments are optionial.
176 *
177 * You can specify one of the following for the first argument:
178 * 0: No compression
179 * 1: Min compression
180 * ... Some compression (integer from 1 to 9)
181 * 9: Max compression
182 * true: Determin the compression level from the system load. The
183 * higher the load the less the compression.
184 *
185 * You can specify one of the following for the second argument:
186 * true: Don't actully output the compressed form but run as if it
187 * had. Used for debugging.
188 *
189 * @param integer $level: Define the level of compression between 0 (none) and 9 (best compression)
190 * @param boolean $debug: If true, no data will be outputted (default: false)
191 * @param boolean $outputCompressedSizes: If true, the original and compressed size appended as HTML (default: false)
192 * @return void
193 * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.6, we're using the "ob_gzhandler" for compression now.
194 */
195 function gzip_encode($level = 3, $debug = FALSE, $outputCompressedSizes = FALSE) {
196 t3lib_div::logDeprecatedFunction();
197
198 if (!function_exists('gzcompress')) {
199 trigger_error('gzcompress not found, ' .
200 'zlib needs to be installed for gzip_encode',
201 E_USER_WARNING);
202 return;
203 }
204 if (!function_exists('crc32')) {
205 trigger_error('crc32() not found, ' .
206 'PHP >= 4.0.1 needed for gzip_encode', E_USER_WARNING);
207 return;
208 }
209 if (headers_sent()) {
210 return;
211 }
212 if (connection_status() !== 0) {
213 return;
214 }
215 $encoding = $this->gzip_accepted();
216 if (!$encoding) {
217 return;
218 }
219 $this->encoding = $encoding;
220
221 if (strtolower($level) == 'true' || $level === TRUE) {
222 $level = $this->get_complevel();
223 }
224 $this->level = $level;
225
226 $contents = ob_get_contents();
227 if ($contents === FALSE) {
228 return;
229 }
230
231 $gzdata = "\x1f\x8b\x08\x00\x00\x00\x00\x00"; // gzip header
232
233 // By Kasper Skårhøj, start
234 if ($outputCompressedSizes) {
235 $contents .= LF . "<!-- Compressed, level " . $level . ", original size was " . strlen($contents) . " bytes. New size is " . strlen(gzcompress($contents, $level)) . " bytes -->";
236 $size = strlen($contents); // Must set again!
237 }
238 // By Kasper Skårhøj, end
239
240 $size = strlen($contents);
241 $crc = crc32($contents);
242 $gzdata .= gzcompress($contents, $level);
243 $gzdata = substr($gzdata, 0, strlen($gzdata) - 4); // fix crc bug
244 $gzdata .= pack("V", $crc) . pack("V", $size);
245
246 $this->size = $size;
247 $this->crc = $crc;
248 $this->gzsize = strlen($gzdata);
249
250 if ($debug) {
251 return;
252 }
253
254 ob_end_clean();
255 Header('Content-Encoding: ' . $encoding);
256 Header('Content-Length: ' . strlen($gzdata));
257 Header('X-Content-Encoded-By: class.gzip_encode ' . $this->_version);
258
259 echo $gzdata;
260 }
261
262
263 /**
264 * gzip_accepted() - Test headers for Accept-Encoding: gzip
265 * Returns: if proper headers aren't found: false
266 * if proper headers are found: 'gzip' or 'x-gzip'
267 *
268 * Tip: using this function you can test if the class will gzip the output
269 * without actually compressing it yet, eg:
270 * if (gzip_encode::gzip_accepted()) {
271 * echo "Page will be gziped";
272 * }
273 * note the double colon syntax, I don't know where it is documented but
274 * somehow it got in my brain.
275 *
276 * @return mixed Returns 'gzip' if the client browser accepts gzip encoding, otherwise false
277 * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.6, we're using the "ob_gzhandler" for compression now.
278 */
279 function gzip_accepted() {
280 t3lib_div::logDeprecatedFunction();
281
282 // Checks, if the accepted encoding supports gzip or x-gzip.
283 // Furthermore a qvalue check is done. "gzip;q=0" means no gzip accepted at all.
284 $acceptEncoding = t3lib_div::getIndpEnv('HTTP_ACCEPT_ENCODING');
285 if (preg_match('/(^|,\s*)(x-)?gzip(;q=(\d(\.\d+)?))?(,|$)/i', $acceptEncoding, $match) && ($match[4] === '' || $match[4] > 0)) {
286 $encoding = 'gzip';
287 } else {
288 return FALSE;
289 }
290
291 // Test file type. I wish I could get HTTP response headers.
292 $magic = substr(ob_get_contents(), 0, 4);
293 if (substr($magic, 0, 2) === '^_') {
294 // gzip data
295 $encoding = FALSE;
296 } elseif (substr($magic, 0, 3) === 'GIF') {
297 // gif images
298 $encoding = FALSE;
299 } elseif (substr($magic, 0, 2) === "\xFF\xD8") {
300 // jpeg images
301 $encoding = FALSE;
302 } elseif (substr($magic, 0, 4) === "\x89PNG") {
303 // png images
304 $encoding = FALSE;
305 } elseif (substr($magic, 0, 3) === 'FWS') {
306 // Don't gzip Shockwave Flash files. Flash on windows incorrectly
307 // claims it accepts gzip'd content.
308 $encoding = FALSE;
309 } elseif (substr($magic, 0, 2) === 'PK') {
310 // pk zip file
311 $encoding = FALSE;
312 }
313
314
315 return $encoding;
316 }
317
318 /**
319 * get_complevel() - The level of compression we should use.
320 *
321 * Returns an int between 0 and 9 inclusive.
322 *
323 * Tip: $gzleve = gzip_encode::get_complevel(); to get the compression level
324 * that will be used with out actually compressing the output.
325 *
326 * Help: if you use an OS other then linux please send me code to make
327 * this work with your OS - Thanks
328 *
329 * @return integer Suggests a level of compression (0..9) for the current situation
330 * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.6, we're using the "ob_gzhandler" for compression now.
331 */
332 function get_complevel() {
333 t3lib_div::logDeprecatedFunction();
334
335 $uname = posix_uname();
336 switch ($uname['sysname']) {
337 case 'Linux':
338 $cl = (1 - $this->linux_loadavg()) * 10;
339 $level = (int) max(min(9, $cl), 0);
340 break;
341 case 'FreeBSD':
342 $cl = (1 - $this->freebsd_loadavg()) * 10;
343 $level = (int) max(min(9, $cl), 0);
344 break;
345 default:
346 $level = 3;
347 break;
348 }
349 return $level;
350 }
351
352 /**
353 * linux_loadavg() - Gets the max() system load average from /proc/loadavg
354 *
355 * The max() Load Average will be returned
356 *
357 * @return float Returns the current load average
358 * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.6, we're using the "ob_gzhandler" for compression now.
359 */
360 function linux_loadavg() {
361 t3lib_div::logDeprecatedFunction();
362
363 $buffer = '0 0 0';
364 $f = @fopen('/proc/loadavg', 'rb');
365 if ($f) {
366 if (!feof($f)) {
367 $buffer = fgets($f, 1024);
368 }
369 fclose($f);
370 }
371 $load = explode(' ', $buffer);
372 return max((float) $load[0], (float) $load[1], (float) $load[2]);
373 }
374
375 /**
376 * freebsd_loadavg() - Gets the max() system load average from uname(1)
377 *
378 * The max() Load Average will be returned
379 *
380 * I've been told the code below will work on solaris too, anyone wanna
381 * test it?
382 *
383 * @return float Returns the current load average
384 * @deprecated since TYPO3 4.3, this function will be removed in TYPO3 4.6, we're using the "ob_gzhandler" for compression now.
385 */
386 function freebsd_loadavg() {
387 t3lib_div::logDeprecatedFunction();
388
389 $buffer = `uptime`;
390 $load = array();
391 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);
392
393 return max((float) $load[2], (float) $load[3], (float) $load[4]);
394 }
395 }
396
397 ?>