File: class.gzip_encode.php

package info (click to toggle)
typo3-src 4.0.2%2Bdebian-3
  • links: PTS
  • area: main
  • in suites: etch-m68k
  • size: 29,856 kB
  • ctags: 33,382
  • sloc: php: 134,523; xml: 6,976; sql: 1,084; sh: 168; makefile: 45
file content (328 lines) | stat: -rw-r--r-- 11,588 bytes parent folder | download | duplicates (2)
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]);
    }
}

?>