Schau dir auch die anderen Artikel an: Zum Leitartikel
Vor einigen Tagen schrieb ich bereits über eine Möglichkeit, die Gravatar-Icons lokal zwischen zu speichern. Leider wurde dabei bei jedem Aufruf eines Bildes immer einen php-call gemacht, was mir bei manchen Beiträgen das Blog in die Knie zwingen würde und dem eigentlich gewünschten Effekt (Beschleunigung) entgegenstehen würde. Daher habe ich mir mal die Funktionen meines Webservers nginx angesehen und dabei festgestellt, dass dieser die folgende Prüfung erlaubt:
- Ist das Bild vorhanden?
- Wenn ja: Direkte Auslieferung
- Wenn nein: Aufruf einer PHP-Datei zum Download des Bildes
Werbung
Die Umsetzung war dann einfach:
Das ist die Konfigurationsdatei für den vHost in nginx:
server { listen 80; server_name img.yourdomain.tld; error_log /path/to/your/logs/error/img.yourdomain.tld.log warn; root /path/to/your/document/root/; location ~ \.php$ { fastcgi_pass 127.0.0.1:1234; include /etc/nginx/fastcgi_params; } location / { index cdn.php; # if the requested file exists, return it immediately if (-f $request_filename) { break; } # all other requests go to CDN-PHP-File if (!-e $request_filename) { rewrite ^(.+)$ /cdn.php last; } } }
Nun speichert man in /path/to/your/document/root/
die Datei cdn.php mit folgendem Inhalt:
<?php // Script by Uli Wolf - https://wolf-u.li <?php $url=explode("/", $_SERVER['REQUEST_URI']); // Type $url[1] = strtolower(preg_replace("/[^a-zA-Z\s]/", "", $url[1])); // Now evaluate the type if(strlen($url[1])==1) { switch($url[1]) { case "g": cache_get_gravatar($url); break; default: exit; break; } } function cache_get_gravatar($url) { $cache['type']=$url[1]; $cache['size']=$url[2]; $cache['hash']=$url[3]; if(!is_dir("./g")) { mkdir("./g"); } // Size $cache['size'] = preg_replace("/[^0-9\s]/", "", $cache['size']); if(!is_dir("./g/" . $cache['size'])) { mkdir("./g/" . $cache['size']); } // Key // - The String looks like: 3c7257f1a8c44frc6oae3ed84cd78a88.png $cache['hash'] = explode(".", $cache['hash']); // - The String looks like: 3c7257f1a8c44frc6oae3ed84cd78a88 $cache['hash'] = preg_replace("/[^a-zA-Z0-9\s]/", "", $cache['hash'][0]); // Check correct string length if(strlen($cache['hash'])!=32) {exit;} // If the mailadress was not found, you can get various images: // - identicon // - monsterid // - wavatar // - mm (mysteryman) $mailnotfound = "mm"; $grav_img = "http://www.gravatar.com/avatar/" . $cache['hash'] . "?s=" . $cache['size'] . "&d=" . $mailnotfound . "&r=G"; if(extension_loaded('curl')) { $gch = curl_init(); $gcurl_options = array( CURLOPT_URL => $grav_img, CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 20, CURLOPT_BINARYTRANSFER => true, CURLOPT_MAXREDIRS => 2 ); curl_setopt_array($gch, $gcurl_options); $gdata = curl_exec($gch); if(!curl_errno($gch)) { $info = curl_getinfo($ch); if(curl_getinfo($gch, CURLINFO_HTTP_CODE) != 200) { echo "Foo"; exit; } } curl_close ($gch); unset($gch); } $gfilehandle_img = fopen("g/" . $cache['size'] . "/" . $cache['hash'] . ".png", "wb+"); fwrite($gfilehandle_img, $gdata); fclose($gfilehandle_img); unset($gfilehandle_img); header('content-type: image/png'); echo $gdata; }
Was macht diese Datei?
Zunächst wird die URL zerlegt und anhand des Typs die Quelle für die Avatare ausgewählt. Warum der Unterordner /g/? Ich wollte mir damit offen halten, verschiedene Bildertypen zu cachen. Das habe ich gelöst, indem ich meinen Bilderhashes ein „/g/
“ vorstelle, welches diese als Gravatar-Bilder markiert. Fällt mir also irgendwann mal ein, dass ich beispielsweise gerne noch Pavatar (wie auch immer geartet) cachen möchte, dann kann ich dies hier einbauen.
Der nächste Teil der URL ist die größe des Avatars, die nur aus Zahlen bestehen darf.
Anschließend wird eine Prüfung der md5-summe der E-Mailadresse durchgeführt, die einige mögliche Angriffsvektoren ausfiltern soll. Dabei bleiben dann nur Strings mit 32 Zeichen in Groß- und Kleinbuchstaben übrig, andernfalls wird das Script beendet. Im Anschluss wird dann das Bild geholt (per curl, wenn möglich), gespeichert und ausgegeben. Das verzeichnis /path/to/your/document/root/g/ sollte hierzu vorhanden sein.
Die Url für ein 32×32 großes Bild sieht also am Ende so aus:
http://img.yourdomain.tld/g/32/a9ec4695d424a6dcb6f896afb0ee22bc.png
und wird bei ersten Aufruf gecached mittels php und anschließend in den weiteren Aufrufen immer statisch durch den Webserver ausgegeben. Möchte man nun regelmäßig die Bilder aktualisieren, empfiehlt es sich, das hier bereits vorgestellte Script in regelmäßigen Abständen laufen zu lassen.
Für den Einbau in WordPress ist das ganze auch recht einfach. Hierzu nimmt man einfach mein WordPress-Plugin wu-get_avatar.
Zu guter letzt noch ein Hinweis für Apache-Nutzer: Das PHP-Script lässt sich natürlich auch mit diesem Webserver nutzen.
Weißt du, ob es eine entsprechende Funktion für Apache gibt?
Sicher, musst dich mal bei den mod_rewrite-Geschichten umschauen 😉
Ähm… nginx ist ursprünglich ein PROXYserver. Und kann ganz alleine Files cachen, ohne PHP-Skripte: siehe proxy_pass, proxy_cache.
Schöne Weihnachten 😉