Bildercache für den Webserver nginx am Beispiel von Gravatar-Icons

Dieser Artikel ist Teil einer Reihe zum Webserver nginx.
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


Die Umsetzung war dann einfach:

Das ist die Konfigurationsdatei für den vHost in nginx:

CODE:
  1. server {
  2.     listen                                  80;
  3.     server_name                             img.yourdomain.tld;
  4.     error_log                               /path/to/your/logs/error/img.yourdomain.tld.log warn;
  5.     root                                    /path/to/your/document/root/;
  6.  
  7.     location ~ \.php$ {
  8.         fastcgi_pass            127.0.0.1:1234;
  9.         include                 /etc/nginx/fastcgi_params;
  10.     }
  11.  
  12.     location / {
  13.         index                           cdn.php;
  14.         # if the requested file exists, return it immediately
  15.         if (-f $request_filename) {
  16.             break;
  17.         }
  18.  
  19.         # all other requests go to CDN-PHP-File
  20.         if (!-e $request_filename) {
  21.             rewrite ^(.+)$ /cdn.php last;
  22.         }
  23.     }
  24. }

Nun speichert man in /path/to/your/document/root/ die Datei cdn.php mit folgendem Inhalt:

CODE:
  1. <?php
  2. // Script by Uli Wolf - http://wolf-u.li
  3.  
  4. // Modify the settings below according to your needs:
  5. // Size of the gravatar-images:
  6. $gimagesize = 32;
  7.  
  8. // If the mailadress was not found, you can get various images:
  9. // - identicon
  10. // - monsterid
  11. // - wavatar
  12. $mailnotfound = "identicon";
  13.  
  14. $removefromurl = array("/g/","/",".png",".jpg",".gif");
  15. $gravatar_hash = str_replace(strtolower($removefromurl),"",$_SERVER["REQUEST_URI"]);
  16. $gravatar_hash = preg_replace("/[^a-z0-9\s]/", "", $gravatar_hash);
  17. if(strlen($gravatar_hash)!=32) {exit;}
  18. $grav_img = "http://www.gravatar.com/avatar/" . $gravatar_hash . "?s=" . $gimagesize . "&d=" . $mailnotfound . "&r=G";
  19. if(extension_loaded('curl')) {
  20.     $gch = curl_init();
  21.     $gcurl_options = array(
  22.         CURLOPT_URL => $grav_img,
  23.         CURLOPT_HEADER => false,
  24.         CURLOPT_RETURNTRANSFER => true,
  25.         CURLOPT_TIMEOUT => 20,
  26.         CURLOPT_BINARYTRANSFER => true,
  27.         CURLOPT_MAXREDIRS => 2
  28.     );
  29.     curl_setopt_array($gch, $gcurl_options);
  30.  
  31.     $gdata = curl_exec($gch);
  32.     curl_close ($gch);
  33.     unset($gch);
  34. } else {
  35.     ob_start();
  36.     $gfilehandle_url = fopen($grav_img, "rb");
  37.     fpassthru($gfilehandle_url);
  38.     fclose($gfilehandle_url);
  39.     $gdata = ob_get_contents();
  40.     ob_end_clean();
  41.     unset($gfilehandle_url);
  42. }
  43. $gfilehandle_img = fopen("g/" . $gravatar_hash . ".png", "wb+");
  44. fwrite($gfilehandle_img, $gdata);
  45. fclose($gfilehandle_img);
  46. unset($gfilehandle_img);
  47.  
  48. header('content-type: image/png');
  49. echo $gdata;
  50. ?>

Was macht diese Datei?

Oben kann man zunächst einstellen, wie groß die Bilder sein sollen und welches Bild angezeigt werden soll, wenn nix hinterlegt ist. Anschließend wird eine Prüfung der URL 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.

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.

Meine Url sieht also am Ende so aus:

http://img.yourdomain.tld/g/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. Man öffnet die comments.php und sucht darin den Aufruf:

CODE:
  1. <?php echo get_avatar( $comment, 32); ?>

Diesen ersetzt man dann durch:

CODE:
  1. <?php echo "<img src='http://img.yourdomain.tld/g/" . md5(strtolower(get_comment_author_email())) . ".png' height='32' width='32'>"; ?>

Wobei die Domain und die Größe natürlich austauschbar sind.

Zu guter letzt noch ein Hinweis für Apache-Nutzer: Das PHP-Script lässt sich natürlich auch mit diesem Webserver nutzen.

2 Antworten zu “Bildercache für den Webserver nginx am Beispiel von Gravatar-Icons”


Eine Antwort hinterlassen

XHTML: Du kannst folgende Elemente benutzen <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> :