Einzelnen Beitrag anzeigen
Alt 20.11.2004, 23:21   #1 (permalink)
Dr. Doom
50 Beiträge
 
Registriert seit: 20.11.2004
Beiträge: 59
Standard [Tutorial] g(e)zip(pt) surft sichs besser

So, dann mach ich noch einen zum Einstand

Ihr kennt das bestimmt. Die Anbindung Eures Servers ist eh schon nicht die Beste. Die Besuchzahlen sind ganz gut und laufend beschweren sich irgendwelche Modemnoobs, dass der Seitenaufbau zu lange dauert. Dann habt Ihr optimiert und gemacht und trotzdem hängen diese nicht DSLler noch 5 Sekunden vor Eurer Seite und warten sich nen Wolf. Das muss nicht so sein.

Seit einige Jahren verwenden moderne Browser ein Verfahren, indem Webseiten on the fly mit gzip gepackt werden und beim User wieder entpackt werden. Da es sich um Textdateien handelt ist diese Methode besonders effektiv. Die Frage ist nur, wie setzt man das am besten um.

Seit PHP 4 gibt es die Möglichkeit die Daten per ob_gzhandler sofort in der Pufferung zu packen. Sie auch da :hier: http://de.php.net/manual/de/function.ob-start.php. Dies ist an sich eine feine Sache, aber nicht immer sinnvoll.

Die größten Nachteile des ob_gzhandlers:
- Man kann den Kompressionsgrad nicht einstellen und ist von den PHP Einstellungen abhängig
- Man kann die Kompression nicht für einzelne Dateitypen ausschalten
- Es gibt in PHP immer wieder Probleme, wenn man den Puffer leeren muss

Also brauchen wir eine extra Klasse/Funktion mit der wir das machen. Das Folgende Script ist nur ein Vorschlag. Es ist in Teilen an dieses da :hier: angelehnt http://leknor.com/code/php/class.gzi...de.0.6.php.txt - nur etwas moderner und mit mehr Einstellungsmöglichkeiten. Ausserdem sollte es auch etwas schneller sein, das hab ich aber nicht getestet. Bugs dürfte es keine mehr geben.

Features:
- minimaler/maximaler Kompressionsgrad einstellbar
- bestimmte Dateitypen werden von der Komprimierung ausgeschlossen
- Die Kompression passt sich an die Serverload an, d. h. ist der Server sehr ausgelastet wird die Kompression runtergesetzt
- die maximale Serverauslastung ist einstellbar
- Auch eine feste Komprimierung ist einstellbar
- Sehr einfache Einbindung
- Bei einem Fehler gibt es keine Einschränkung. Es wird einfach nur der Content ausgegeben
- kompatibel mit allen PHP Versionen ab Version 4 mit zlib Bibliothek
- Ihr könnt zusätzliche Informationen über die Bearbeitung anzeigen (Serverload, CPU Time, Kompression, Ersparnis)

Die Einbindung
Ganz unten seht Ihr einen Beispielcode, wie Ihr das einbinden könnt.

Code:
<?php

/**
 * This class checks the output buffer 
 * zips the input if you want to
 * @param: int $MaxServerload the maximum serverload
 * @param: int $MinCompression the minimum compression level
 * @param: int $MaxCompression the maximum compression level
 * @input: mixed $level the compression level
 * @input: bool $debug use debug mode (no compression)
 * @input: bool $showSize show the compression in html
 * @return: string the output
 */
class Output
{
	/**
	 * Public vars
	 */
	var $MaxServerload = '2';
	var $MinCompression = '2';
	var $MaxCompression = '8';
	/**
	 * Private vars
	 */
	var $contents;
	var $gzdata;
	var $encoding;
	var $crc;
	var $size;
	var $gzsize;
	var $serverload;
	var $level;
	var $debug;
	var $showSize;

	/**
	 * Constructor
	 */
	function Output($level='3', $debug=false, $showSize=true)
	{
		$this->level = $level;
		$this->debug = $debug;
		$this->showSize = $showSize;
	}

	/**
	 * Let's work a bit with the buffer
	 * @input string $buffer the output buffer
	 * @return string $buffer the new output buffer
	 */
	function gz($buffer)
	{
		$this->contents = $buffer;

		/* Find out which encoding to use */
		$this->encoding = false;

		/**
		 * Check the best compress version for the browser
		 * Use the @ to prevent bots from saving an error
		 */
		if (isset($_SERVER['HTTP_ACCEPT_ENCODING']))
		{
			if(@strpos(' ' . $_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false)
			{
				$this->encoding = 'x-gzip';
			}
			if(@strpos(' ' . $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false)
			{
				$this->encoding = 'gzip';
			}
		}

		/* Find out more about the file which should be compressed */
		$filetype = substr($this->contents, 0, 4);

		if(substr($filetype, 0, 2) === '^_')
		{
			/* gzip data */
			$this->encoding = false;
		}
		elseif(substr($filetype, 0, 3) === 'GIF')
		{
			/* gif images */
			$this->encoding = false;
		}
		elseif(substr($filetype, 0, 2) === "\xFF\xD8")
		{
			/* jpeg images */
			$this->encoding = false;
		}
		elseif(substr($filetype, 0, 4) === "\x89PNG")
		{
			/* png images */
			$this->encoding = false;
		}
		elseif(substr($filetype, 0, 3) === 'FWS')
		{
			/* Shockwave Flash */
			$this->encoding = false;
		}
		elseif(substr($filetype, 0, 2) === 'PK')
		{
			/* pk zip file */
			$this->encoding = false;
		}
		elseif($filetype == '%PDF')
		{
			/* PDF File */
			$this->encoding = false;
		}

		/* There might be some Problems */
		if(headers_sent() || connection_status() != 0 || !$this->encoding || $this->contents === false || !extension_loaded('zlib') || @ini_get('output_handler') == 'ob_gzhandler')
			return $this->contents;

		/* We need a level to compress the output */
		if($this->level == 'auto')
		{
			/* Let's find out, which compression level is ok for the system */
			if(@file_exists('/proc/loadavg'))
			{
				$fh = @fopen('/proc/loadavg', 'r');
				$load_averages = @fread($fh, 64);
				@fclose($fh);
			
				$load_averages = @explode(' ', $load_averages);
				$this->serverload = ((float)$load_averages[0]+(float)$load_averages[1]+(float)$load_averages[2])/3;
			}
			elseif(preg_match('/averages?: ([0-9\.]+),[\s]+([0-9\.]+),[\s]+([0-9\.]+)/i', @exec('uptime'), $load_averages))
			{
				$this->serverload = ((float)$load_averages[1]+(float)$load_averages[2]+(float)$load_averages[3])/3;
			}
			else
			{
				$this->serverload = '1';
			}
	
			$this->level = (1-($this->serverload/$this->MaxServerload))*10;
	
			/* Ok, that looks terrible, but its faster than a min/max construction */
			$this->level = ($this->level > $this->MinCompression) ? (($this->level < $this->MaxCompression) ? intval($this->level) : $this->MaxCompression) : $this->MinCompression;
		}

		/* The introduction for the compressed data */
		$this->gzdata = "\x1f\x8b\x08\x00\x00\x00\x00\x00";

		/**
		 * Maybe you want some extra information
		 * This is not the ideal because you need to 
		 * compress the output twice
		 */
		if($this->showSize)
		{
			/* We need some vars for the information */
			$uncompressed	= round(strlen($this->contents)/1024, 2);
			$start		= get_microtime();
			$compressed	= round(strlen(gzcompress($this->contents, $this->level))/1024, 2);
			$time		= round((get_microtime()-$start)*1000, 2);
			$savingkb	= $uncompressed-$compressed;
			$saving		= @round($savingkb/$uncompressed*100, 0);
			$showlevel	= ($this->level == 'auto') ? ' (auto)' : '';

			/* Shows some informations */
			$this->contents .= "\n".'<!--'."\n\t".'Compression level: '.$this->level.$showlevel."\n\t".'Original size: '.$uncompressed.' kb'."\n\t".'New size: '.$compressed.' kb'."\n\t".'Saving: '.$savingkb.' kb ('.$saving.' %)'."\n\t".'Time: '.$time.' ms'."\n\t".'Serverload: '.round($this->serverload, 2)."\n".'-->';
		}

		/* Compress the output */
		$this->size	= strlen($this->contents);
		$this->gzdata	.= substr(gzcompress($this->contents, $this->level), 0, - 4);
		$this->gzdata	.= pack('V', crc32($this->contents));
		$this->gzdata	.= pack('V', $this->size);
		$this->gzsize	= strlen($this->gzdata);

		/* Maybe you just want to see the result of all this */
		if($this->debug)
		{
			$this->contents = $this->contents."\n".'<!--'."\n\t".'gzip is in debug mode. The shown output is uncompressed'."\n".'-->';
			return $this->contents;
		}

		/* Send the special header */
		header('Content-Encoding: '.$this->encoding);
		header('Content-Length: '.$this->gzsize);

		/* Exit the class and send all data to the browser */
		return $this->gzdata;
	}

}
/**
 * construct the object
 */
$output = new Output('auto', false, true);

/**
 * Start the output buffering
 */
ob_start(array(&$output, 'gz'));

?>
Viel Spaß damit .

Geändert von Dr. Doom (20.11.2004 um 23:24 Uhr).
Dr. Doom ist offline   Mit Zitat antworten