HX3 Foren  

  HX3 Foren > Konstruktiv > Software- und Webentwicklung

Software- und Webentwicklung Planung, Programmierung und Administration
UML, JavaScript/DOM, ASP, JSP, PHP, Apache, MySQL, Python, Perl (...)

Antwort
 
Themen-Optionen Ansicht
Alt 20.11.2004, 23:21   #1 (permalink)
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
Alt 21.11.2004, 09:50   #2 (permalink)
Administrator 10 Jahre hx3
5000 Beiträge
 
Benutzerbild von Atomic
 
Registriert seit: 21.02.2003
Ort: Freiburg im Breisgau
Alter: 33
Beiträge: 5.139
Atomic eine Nachricht über ICQ schicken Atomic eine Nachricht über Skype™ schicken
Standard AW: [Tutorial] g(e)zip(pt) surft sichs besser

Erwähnen sollte man vielleicht noch das die Klasse ebenfalls wie ob_gzhandlers nachcheckt ob der Client (Browser) überhaupt in der Lage ist komprimierte Inhalte zu lesen.
Du verwendest für meinen Geschmack ein paar "@" zuviel.
Du könntest auch wenn du die Fehlerausgabe verhindern willst die komplette Fehlerausgabe deaktivieren:
PHP-Code:
<?php
 $old_errorlevel 
error_reporting(~E_ALL); //..alles deaktivieren
 
$fp fopen("gibts_nicht","r"); //Der Fehler wird niemals erscheinen
 
error_reporting($old_errorlevel); //.. den alten Error Level wieder setzen
 
$fp fopen("gibts_auch_nicht","r"); //Dieser Fehler wird erscheinen
 
?>
Allerdings wäre es noch besser wenn du zumindest die Fehler in eine Datei schreiben lässt.
Da hättest du jetzt bei PHP 5 leichtes Spiel (=> Exception Handling).

Ansonsten #1
Schön zu sehen das hier Jemand mal etwas postet. *rolleyes*
__________________
http://webagentur-walde.de/
Atomic ist offline   Mit Zitat antworten
Alt 21.11.2004, 12:31   #3 (permalink)
500 Beiträge1000 Beiträge
 
Benutzerbild von Daedalus
 
Registriert seit: 04.03.2003
Alter: 30
Beiträge: 1.415
Daedalus eine Nachricht über ICQ schicken
Standard AW: [Tutorial] g(e)zip(pt) surft sichs besser

Es gibt eben nicht viele die das verstehen. -.-
__________________
Daedalus ist offline   Mit Zitat antworten
Alt 21.11.2004, 13:46   #4 (permalink)
50 Beiträge
 
Registriert seit: 20.11.2004
Beiträge: 59
Standard AW: [Tutorial] g(e)zip(pt) surft sichs besser

Fürs Error Reporting hab ich eine eigene Klasse, die mir die Fehler loggt und wenn ich das will auch direkt den fehlerhaften Quelltext anzeigt. 2 @s könnten weg - das stimmt schon.
Dr. Doom ist offline   Mit Zitat antworten
Alt 30.05.2009, 22:15   #5 (permalink)
Newbie
 
Registriert seit: 30.05.2009
Beiträge: 4
Standard

Zitat von Dr. Doom Beitrag anzeigen

Fürs Error Reporting hab ich eine eigene Klasse, die mir die Fehler loggt und wenn ich das will auch direkt den fehlerhaften Quelltext anzeigt. 2 @s könnten weg - das stimmt schon.


Hallo Dr. Doom,

ist zwar lange her, dass du diesen Tutorial hier gepostet hast womit ich dir auch sehr Dankbar bin.
Habe so was ähnliches eigentlich gesucht und ist dir echt sehr gut gelungen.

Doch wäre ich ebenfalls sehr an deinem Error Reporting Klasse auch interessiert.
Da es zu deinem Output Klasse passt.

Wäre dir sehr Dankbar, wenn du dieses ebenfalls veröffentlichen würdest oder eventuell vielleicht auch mir per Email schicken würdest.

Gruß
Daniel
crashbraker ist offline   Mit Zitat antworten
Antwort


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen
Ansicht

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus


Kontakt - HX3.de - Archiv - Nach oben

Angetrieben durch vBulletin, Entwicklung von Philipp Dörner & Tobias



SEO by vBSEO 3.2.0 ©2008, Crawlability, Inc.

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