Tag "php"

Ä zu AE – Umlaute mit PHP umwandeln

15. Oktober 2008

Alle Nase lang muss man als Webdeveloper Sonderzeichen gärtnern. Muss man in PHP Umlaute loswerden, ein „ß“ verschwinden lassen, einen dieser Ausnahmebuchstaben tilgen – um z.B. schicke URLs wahr werden zu lassen. Oft muss es eben ACSII sein, und das ist halt ein beschissen kleiner Zeichenvorrat von 128 Zeichen. Da ist an Umlaute nicht zu denken.

Das kann man machen, indem man sich große Tabellen anlegt und weitläufiges Suchen & Ersetzen durchführt. Ein „ä“ wird da zu „ae“, ein „ß“ zu „ss“ und so fort. Will man das richtig machen, kann man da herrlich lange Zeit mit dem Tippen von Vorher/Nachher-Zuordnungen verbringen. Super. Muss man das nun unbedingt selber durchexerzieren?

Kann PHP das vielleicht ab Werk selber erledigen? Ja, doch! Das iconv-Modul bringt so einiges mit, um Zeichenketten zwischen Kodierungen hin- und herzuwandeln. Vor allem beherrscht die Funktion iconv() die Fähigkeit zur Transliteration. Das bedeutet, dass ein Zeichen welches im Ziel-Zeichensatz nicht zur Verfügung steht, durch ähnliche Zeichen ersetzt wird. Durch Anhängen von „//TRANSLIT“ an den Zielzeichensatz bringt man die Funktion dazu, die speziellen Zeichen nicht zu verwerfen, sondern umzuwandeln:

<?php
$satz = "Olé Garçon! Diese Süßspeise schmeckt gar nicht übel! *börp*";
print (iconv("UTF-8", "ASCII//TRANSLIT", $satz));
?>

Das ergibt diese Zeichenfolge (wohlgemerkt wenn die PHP-Datei in UTF-8 kodiert ist):
Ole Garcon! Diese Suessspeise schmeckt gar nicht uebel! *boerp*

Na bitte!

iconv()-Dokumentation

gz-Kompression für statische Dateien mit Apache und PHP

26. Februar 2007

„Der erste Eindruck zählt“ gilt bei einer Website nicht nur für die Optik, sondern auch für die Geschwindigkeit mit der die Seite geladen wird. Und auch trotz schlankem Quellcode bringt eine Webseite mit all ihren Bildern, Stylesheets, Javascript-Frameworks schnell eine stattliche Größe von mehreren 100KByte auf die Waage, die erstmal durch die Leitung müssen.

Dann schlägt beim Apache-Webserver eigentlich die Stunde für Module wie mod_gzip oder mod_deflate, die für Kompression bei der Übertragung zuständig sind. Gerade diese Helferlein stehen beim Billighoster aber höchst selten zur Verfügung. Der Hoster muss in der Regel mit seiner Prozessorkraft haushalten – und wo käme man da hin, wenn jeder so mirnichts–dirnichts Rechenpower für das Komprimieren von Daten abzweigen kann (um Traffic zu sparen, den man genausogut teuer verkaufen kann)?

Scripte & Stylesheets komprimieren
Scripte und Stylesheets schreien dabei geradezu nach komprimierter Übertragung, bestehen sie doch aus Kompressions-freundlichem ASCII-Gebräu. Wie kriegt man diese Dateien also klein, ohne mod_gzip / mod_deflate zu bemühen?

Kompression mit PHP
Nun gut – dann muss der PHP-Interpreter herhalten: Kompression anschalten, Dateiinhalt ausgeben ausgeben (natürlich mit dem entsprechenden Header), fertig.

Als Beispiel soll mal die Datei „prototype.js“ des Prototype-Frameworks herhalten, die unkomprimiert immerhin an die 72KByte auf die Waage bringt.

ob_start("ob_gzhandler");
header('Content-Type: text/javascript');
print (...); //JavaScript-Code ausgeben

Und siehe da: der Firefox weist ca. 15KByte übertragene Daten aus – „mal eben“ 80% Ladezeit gespart …

Schönheitsfehler Dateiendung
Abzüge in der B-Note gibt es für die falsche Dateiendung: damit die umgepolte Javascript-Datei vom PHP-Parser verarbeitet wird, muss die Endung .php sein. Da weisen wir den Apache per .htaccess-Datei doch lieber gleich darauf hin, dass .js-Dateien ab jetzt PHP-Code enthalten:

AddType application/x-httpd-php .js .php

(Obacht: die Art, wie dies eingestellt wird kann schonmal von Hoster zu Hoster verschieden sein.)

Kompression ohne Caching ist Quatsch
Indem ich alle .js-Dateien zu dynamische Seiten „befördere“, kann die Datei nicht mehr gecached werden und wird bei jedem Seitenaufruf neu geladen. Oopsie! In meinem Beispiel habe ich also schlimmstenfalls nach 5 Seitenimpressionen a 15KByte den gewonnenen Vorteil wieder verspielt. Wer „A“ sagt, muss also auch …

… den Browser zum Cachen ermuntern
Header-Informationen über den Zeitpunkt der letzten Änderung an der Datei kann der Webserver nicht an den Browser senden, weil wir PHP benutzen – dynamische Seiten ändern sich eben ständig!
Das erledigen wir also von Hand, indem wir den entsprechenden „Last-Modified“ Header selbst erzeugen.

Und damit das auch den gewünschten Effekt zeigt, müssen wir vor der Ausgabe des Dateiinhalts prüfen, ob der Browser noch eine aktuelle Version besitzt („If-modified-since“-Header). Ist das der Fall, senden wir eine „304 Not Modified“-Antwort – die Datei muss nicht übertragen werden, Zeit und Traffic werden gespart. Hurrah!

Es kommt noch besser: mit der HTTP::Header::Cache() Klasse aus dem PEAR-Repository bringt man seinen dynamischen Dateien im Handumdrehen statische Verhaltensweisen bei und muss nicht das Rad neu erfinden:

require('HTTP/Header/Cache.php');
$header = new HTTP_Header_Cache(1,'days');
$header->sendHeaders();
$date=HTTP::date();

Das „Haltbarkeitsdatum“ der Datei setze ich einfach mal auf 24 Stunden an. Die Cache-Klasse prüft nun, ob der Browser noch eine gültige Version der Datei besitzt – ist das der Fall, wird der besagte 304-Header abgesendet und das Script beendet.

Plug & Play
Alle seine Scripte und Stylesheets mit PHP-Code vollzustopfen macht auch nicht grade viel Spaß. Darum weise ich den Server per .htaccess-Datei an, in meinem Script-Ordner allen PHP-Dateien automatisch die Datei prepend.php voranzustellen.

php_value auto_prepend_file prepend.php

Da sich alle zum Einleiten der Kompression nötigen Schritte vor der Ausgabe abspielen (logisch), brauche ich die zu komprimierenden Dateien auf diese Art gar nicht ändern. Einen bitteren Nachgeschmack hinterlässt, dass der PHP-Interpreter die nachfolgende Script/Stylesheet-Datei vergeblich nach PHP-Code durchwühlt. Da bleibt noch Raum für spannende Verbesserungen, aber das soll uns erstmal nicht interessieren.

Diese Lösung gewinnt vielleicht keine Benchmarks, trägt aber vielleicht ein wenig zur verbesserten Benutzererfahrung bei.