Gravatare mit PHP cachen

In meinem Blog verwende ich schon lange den Dienst Gravatar. Dadurch wird zu den Kommentaren ein Bild (Avatar) vom Kommentator angezeigt. Vorausgesetzt, eine Mailadresse wird angegeben und ein Avatar ist bei Gravatar auf diese Adresse registriert. Beim Aufruf meiner Seite wir dieser Avatar von der Gravatarseite geholt und angezeigt.

Für den Benutzer hat das den Vorteil, dass er sich nur an einem Ort registrieren muss und dann auf allen Seiten die Gravatar unterstützen einen Avatar hat. Die Mailadresse bleibt dabei immer geschützt, da sie vor der Übertragung in einen MD5 String umgewandelt wird.

Auch für den Webseitenbetreiber hat Gravatar einige Vorteile. So muss man kein eigenes Avatarsystem zusammenbauen und kann einfach Gravatar nutzen. Das ganze ist sehr einfach zu realisieren. Für Wordpress gibt es ja auch Plugins.

Der Nachteil ist allerdings, dass Gravatar halt auf einer anderen Seite läuft. Sollte diese Seite mal Trafficprobleme haben, oder gar ganz down sein, so wir die eigene Seite auch langsam, da die Bilder nicht geladen werden können. Dieses Problem kann man umgehen, indem man die Bilder in einem Cache abspeichert. Ich habe ein PHP Script geschrieben, welches diese Bilder in einen Cache speichert.

Der Ablauf sieht so aus. Zuerst überprüft das Script, ob sich das Bild schon im Cache befindet. Zur Identifizierung wird die Mailadresse als MD5 String verwendet. Ist das Bild schon im Cache und nicht älter als zwei Tage wird das Bild ausgegeben.
Anders sieht es aus, wenn das Bild noch nicht im Cache, oder schon älter als zwei Tage ist. Dann wir eine Verbindung zum Gravatarserver hergestellt, das Bild heruntergeladen und im Cache gespeichert. Dann wird es auch ausgegeben.

Mir ist klar, dass es (noch) keine perfekte Lösung ist, aber es funktioniert. Natürlich kann man so auch andere Bilder (nicht von Gravatar) cachen. Man muss halt einige Angaben anpassen.

Nun müssen sich nur noch mehr Leute bei Gravatar anmelden.

Hier der Code des Scripts:
<?

// Konfiguration
define("CACHE_FOLDER","cache/");                // cache ordner
define("CACHE_DURATION",48);                    // wie lange die bilder im cache bleiben sollen (tage)
define("GRAVATAR_OPTIONS","size=64&amp;");      // optionen (bild groesse, rating usw)

// ueberprufen ob die mailadresse (als md5 string) gesetzt ist
if(!isSet($_GET['address']))
{
    die(
"no address is set");
}

// cache dauer in sekunden umrechnen
$duration_secs=CACHE_DURATION*60*60;

// adresse ueberpruefen
$address=$_GET['address'];
if(!
preg_match("/[a-z0-9]*/i",$address))
{
    die(
"wrong address");
}

define("GRAVATAR_HOST","www.gravatar.com");
define("GRAVATAR_PATH","/avatar.php?".GRAVATAR_OPTIONS."gravatar_id=".$address);
$filename=CACHE_FOLDER.$address.".jpg";

// ueberprufen, ob die datei heruntergeladen werden muss
$download=TRUE;
if(
file_exists($filename))
{
    if(
fileMTime($filename)>(time()-$duration_secs))
    {
        
$download=FALSE;
    }
}

// wenn ja
if($download)
{
    
// zum host verbinden
    
$source=@fSockOpen(GRAVATAR_HOST,80,$errno,$errstr,30);

    
// wen verbindung hergestellt
    
if($source!=FALSE)
    {
        
// zu sendende headers zusammenstellen
        
$req ="GET ".GRAVATAR_PATH." HTTP/1.0\r\n";
        
$req.="Host: ".GRAVATAR_HOST."\r\n";
        
$req.="Connection: Close\r\n\r\n";

        
// headers senden
        
fWrite($source,$req);
        
        
// headers der antwort auslesen
        
while(!fEof($source))
        {
            
$header=trim(fGets($source,1024));
            if(
$header=="")
            {
                break;
            }
        }

        
// zieldatei oeffnen
        
$dest=fOpen($filename,"w+");

        
// daten auslesen und direkt in die zieldatei schreiben
        
while(!fEof($source))
        {
            
$data=fGets($source,1024);
            
fWrite($dest,$data);
        }

        
// verbindung trennen
        
fClose($source);
        
fClose($dest);
    }
    else
    {
        
// wenn gravatar down und kein bild im cache
        // standardbild verwenden
        
$filename="gravatar.jpg";
    }
}

// Bild ausgeben.
header("Content-type: image/jpeg");
echo 
file_get_contents($filename);
?>

Bilder mit ImageMagick unter Linux verkleinern

Letzthin habe ich einen Beitrag über ein PHP Script geschrieben, welches automatisch Bilder verkleinert. Dank eine Hinweis von Boje bin ich dann zu diesem Artikel über Script-Fu gekommen. Eigentlich geht es dort darum, wie man Bilder automatisch im Gimp verkleinert, allerdings hat es oben ein kurzes Shellscript, welches zeigt wie man ein Bild mit dem Befehl convert verkleinert. Und das ist einiges simpler als meine PHP-Lösung. Das Script erfüllt allerdings nicht ganz meine Anforderdungen, also habe ich es noch etwas angepasst. convert ist ein Bestandteil von ImageMagick also muss man das zuerst installieren, falls das nicht nicht geschehen ist.
sudo apt-get install imagemagick

Das Script ist dann relativ schnell gemacht und es ist doch einiges simpler und kürzer als die PHP Version. Und sie funktioniert genauso gut.
#!/bin/bash

# Alle .jpg Dateien auslesen
for file in *.jpg
do
    # Thumbnail erstellen
    convert ${file} -resize x150 `basename $file .jpg`_thumb.jpg

    # Die grosse Datei verkleinern
    convert ${file} -resize x600 ${file}
done

Bilder mit PHP unter Linux verkleinern

Hier im Blog poste ich ja sehr oft Bilder. Meistens sind es selbst gemacht. Nur kann ich diese Bilder nicht einfach von der Kamera herunterkopieren und dann auf den Server laden, nein, ich muss sie auch noch etwas bearbeiten. Meistens beschränkt sich dieses Bearbeiten nur auf das verkleinern. Normalerweise gibt es für jedes Bild zwei Bilder. Ein grösseres mit einer Höhe von 600 Pixel und ein Thumbnail mit einer Höhe von 150 Pixel. Nun habe ich diese Bilder immer im Gimp verkleinert, aber das ist mir jetzt zu dumm geworden. Jedes Bild öffnen, verkleinern, speichern, für das Thumbnail nochmals verkleinern und wieder speichern. sehr aufwändig.
Um das ganze nun etwas zu vereinfachen, habe ich mir ein Script geschreiben, welches alle Bilder in einem Ordner verkleinert. Es gibt wieder zwei Bilder mit den schon genannten Grössen. Da ich nur in PHP weiss wie man so etwas macht, hab ich ein kleines PHP Script geschrieben. Der Quelltext ist weiter unten zu finden. Für das Script wird die GD Library benötigt, welche aber standardmässig schon installiert ist. Zudem habe ich noch die CLI (Command Line Interpreter) Version von PHP installiert, so kann ich das Script wie ein normales Shellscript starten. Bei fertigen Script musste ich nur noch die Dateiendung entfernen und die Datei ausführbar machen (chmod 755). Jetzt kann ich die Datei mit einem Doppelklick ausführen und so werden meine Bilder ohne grossen Aufwand verkleinert. Ein hoch auf die Technik ;)

Nun aber noch der PHP-Code:
#!/usr/bin/php -q
<?
// Ordner
define("FOLDER","./");

// Funktion zum verkleinern der Bilder
function thumb($orig,$thumb,$height)
{
    
// Vorherige Groesse
    
$size=getImageSize(FOLDER.$orig);
    
$orig_width=$size[0];
    
$orig_height=$size[1];

    
// Bild laden
    
$src=imageCreateFromJpeg(FOLDER.$orig);

    
// Neue Groesse bestimmen
    
if($orig_height>$height)
    {
        
$factor=$orig_height/$height;

        
$new_height=round($orig_height/$factor,2);
        
$new_width=round($orig_width/$factor,2);
    }

    
// Zielbild erstellen
    
$dst=imageCreateTrueColor($new_width,$new_height);

    
// Bild kopieren
    
$buffer=imageCopyResized($dst,$src,0,0,0,0,$new_width,$new_height,$orig_width,$orig_height);

    
// Bild speichern
    // Qualitaet ist 85%
    
imageJpeg($dst,FOLDER.$thumb,85);
}

// Order oeffnen
$dir=openDir(FOLDER);

// Ordner durchgehen
while($object=readDir($dir))
{
    
// Wenn Datei im jpg endet
    
if(subStr($object,-3,3)=="jpg")
    {
        
$orig=$object;

        
// Name fuer Thumb bestimmen
        // Aus test.jpg wird test_thumb.jpg
        
$split=explode(".",$object);
        unSet(
$split[count($split)-1]);
        
$thumb=implode(".",$split)."_thumb.jpg";

        
// Bilder verkleinern
        
thumb($orig,$thumb,150);
        
thumb($orig,$orig,600);
    }
}
?>

Bilder mit JavaScript preloaden

Ich versuche momentan eine kleine und simple Galerie zu Programmieren. Ein PHP Script soll die Bilder aus eine Verzeichnis auslesen und dann mit Lightbox anzeigen. Der Nachteil von Lightbox ist aber, dass es erst funktioniert, wenn die Seite komplett geladen ist. Und wenn es da mehrere Bilder gibt, kann das Laden der Seite auch mal länger dauern und die wenigsten Besucher wollen da warten.
Ich versuche diese Problematik nun mit einem Preloader zu umgehen. Bisher ohne grossen Erfolg. Aber immerhin weiss ich jetzt, wie man Bilder mit JavaScript "preloadet."
<script language="JavaScript" type="text/javascript">
    <!--
        if (document.images)
        {
            preload_obj=new Image();
            preload_obj.src="images/test.jpg";
        }
    //-->
</script>

Recht simpel. Es wird ein neues Objekt erstellt und danach mit src die Quelle der Datei zugewiesen. Natürlich kann man so mit PHP auch mehrere Bilder preloaden.

Trafficklau mit htaccess verhindern

Das Szenario ist wohl manchen Webdesigner bekannt. Bilder die man auf dem eigenen Webserver hat, werden von anderen Leuten direkt eingebunden. Dies führt zu einem erhöhten Traffic, denn man schlussendlich ja selber bezahlt. Derjenige, der das Bild auf einer anderen Webseite einbindet gibt kaum die Quelle an und zahlt natürlich auch nichts an die höheren Traffickosten. Ich habe bereits früher über einige Möglichkeiten zum verhindern von Trafficklau berichtet. Nun habe ich noch eine andere Möglichkeit. Mittels einer htaccess Datei werden Zugriffe mit bestimmten Referer auf Bilder geblockt. Dies setzt einen Apache Webserver voraus.
# kein zugriff auf bilder fuer die angegebenen referer
<Files ~ "\.(gif|GIF|jpg|JPG|bmp|BMP|jpeg|JPEG|pdf|PDF)$">
    SetEnvIfNoCase Referer bbs bilderklau=yes
    SetEnvIfNoCase Referer ebay bilderklau=yes
    SetEnvIfNoCase Referer foren bilderklau=yes
    SetEnvIfNoCase Referer forum bilderklau=yes
    SetEnvIfNoCase Referer gamez bilderklau=yes
    SetEnvIfNoCase Referer guestbook bilderklau=yes
    SetEnvIfNoCase Referer jappy.de bilderklau=yes
    SetEnvIfNoCase Referer kwick.de bilderklau=yes
    SetEnvIfNoCase Referer live.com bilderklau=yes
    SetEnvIfNoCase Referer mybbforo bilderklau=yes
    SetEnvIfNoCase Referer myspace bilderklau=yes
    SetEnvIfNoCase Referer phpBB bilderklau=yes
    SetEnvIfNoCase Referer viewtopic.php bilderklau=yes

    deny from env=bilderklau
</Files>

Mit imgRed gibt es zudem ein Service im Internet, mit dem man zwar Bilder, aber nicht den Traffic klauen kann. Als Bildadresse gibt man die Adresse mit vorangestellter imgRed Adresse an. Zum Beispiel so:
http://imgred.com/http://plog.t-error.ch/images/35.jpg

Da imgRed das Bild aber Cached, wird dem Besitzer des Webspaces zwar kein Traffic gestohlen, das Bild aber immer noch. Dies lässt sich aber auch mit htaccess ganz einfach verbieten:
# imgRed blocken
order allow,deny
deny from 64.131.64.202
allow from all

Bilder mit Schatten

Integra Square
Auf der Suche nach einer guten Lösung um Bilder mit Schatten zu versehen, bin ich über diese beiden Lösungen gestolpert. Bei der ersten werden mehrere divs verwendet, um einen schönen Schatteneffekt zu erzeugen. Ähnlich wie bei den gerundeten Ecken. Dami kann man Schatten rund um das Bild herum erzeugen.

Die andere Lösung benutzt ein einziges, allerdings recht grosses Hintergrundbild, das den Schatten darstellt. Dies hat den Nachteil, dass die Bildgrösse beschränkt ist, allerdings wird nur ein div verwendet. Zudem ist ein Hintergrundbild, dass die grösse von 1000x1000 Pixel hat nur rund 4Kb gross.

Ich suche allerdings noch eine Lösung, die gar keine divs benötigt. Allerdings muss man dafür noch auf CSS 3 warten. Und vorallem auf die Umsetzung in den Webbrowsern.

Bilder-/Trafficklau verhindern

Über Konnichi wa bin ich auf ein Thema gestossen, dass mich früher auch mal beschäftigte. Der Bilderklau.
Eigentlich gib es zwei Varianten von Bilderklau. Das Bild wird abgespeichert und auf dem eigenen Server gehostet oder das Bild wir einfach verlinkt. Die zweite Varianten nennt man auch Traffic-Klau und darauf möchte ich nun genauer eingehen.

Zum einen gibts da die Möglichkeit, die Bilder einfach umzubenennen und/oder einfach ein anderes Bild an der Stelle platzieren. Diese Variante ist einfach, bringt langfristig aber wenig, da man einfach auf das neue Bilder verlinken kann.

Eine andere Methode habe ich bei Webmaster Resource gefunden. Dort wird das Bild mit PHP in mehrere Stücke zerlegt und dann mit einer Tabelle angezeigt. Für einen Anfänger wird es so schwieriger, da er nicht einfach auf das Bild linken kann, sondern den ganzen Code kopieren muss. Für einen erfahrenen Webdesign allerdings kein Problem.

Eine auch schon sehr bekannte Variante ist die folgende. Man macht eine Tabelle, definiert das zu schützende Bild als Hintergrund und legt ein transparentes Bild davor. Wie schon die Variante davor, nützt das nichts gegen erfahrene Webdesigner. Ein Beispielcode sieht so aus:
<table background="img/bild.jpg">
  <tr>
    <td>
      <img src="img/transparentes_bild.gif" width="200" height="150" alt="" />
    </td>
  </tr>
</table>


Eine effektivere Methode ist htaccess. Damit wird der Referer, also die Seite von der der Besucher kommt, abgefragt. Wenn der Referer nicht die eigene Seite ist, wird ein anderes Bild angezeigt. Einfach und effektiv, funktioniert aber leider nur mit Apache und mod_rewrite.
RewriteEngine OnRewriteCond %{HTTP_REFERER} !^http://.*webseite\.ch/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://.*webseite\.ch*$ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule ^(.*)jpg$ http://www.webseite.ch/images/bilderklau.jpg [L,R]


Fazit:
Wirklich verhindern, kann man den Bilderklau nicht. Allerdings kann man mit wenig Aufwand zumindest den Trafficklau vermindern.

Gerundete Ecken mit CSS

Ich bin auf der Suche nach einer guten Lösung um die ecken von einem Block abzurunden. Dazu gibts ja bekanntlich mehrere Möglichkeiten. Zum Beispiel mit Tabellen, JavaScript und zum Glück auch mit CSS.


Eine Lösung, die gut aussieht, findet man unter Sova v siti. Allerdings gruselt es mich, wenn ich diesen HTML-Code sehe:
<div class="uedge">
  <div class="redge">
    <div class="bedge">
      <div class="ledge">
        <div class="ulcorner">
          <div class="urcorner">
            <div class="blcorner">
              <div class="brcorner">
                <div class="innercontent">
                  <p>Content of the box goes here.</p>
                  <p>The box can be of any width and height. The width of this one is 40% of its containing block.</p>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

Varianten, die mir besser gefallen sind hier und hier zu finden.
Eine Lösung, die ohne Bilder auskommt, aber leider nur mit dem Mozilla funktioniert gibts auch

Und zum Schluss noch eine Liste mit mehreren zusätzlichen Lösungen.