HX3 Foren

HX3 Foren (https://hx3.de/)
-   Software- und Webentwicklung (https://hx3.de/software-webentwicklung-23/)
-   -   [Tutorial] g(e)zip(pt) surft sichs besser (https://hx3.de/software-webentwicklung-23/tutorial-g-e-zip-pt-surft-sichs-besser-9764/)

Dr. Doom 20.11.2004 23:21

[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 :).

Atomic 21.11.2004 09:50

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 :daumen:
Schön zu sehen das hier Jemand mal etwas postet. *rolleyes*

Daedalus 21.11.2004 12:31

AW: [Tutorial] g(e)zip(pt) surft sichs besser
 
Es gibt eben nicht viele die das verstehen. -.-

Dr. Doom 21.11.2004 13:46

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. :)

crashbraker 30.05.2009 22:15

Zitat:

Zitat von Dr. Doom (Beitrag 57923)
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


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:48 Uhr.

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 117 118