Beim Aufräumen meiner noch recht übersichtlichen Website ist mir phpCountIPTC aufgefallen. Was genau soll das sein? Diese Idee – mal abgesehen davon, daß die entsprechende Seite seit dem Jahr 2003 vor sich hinexistiert – ist entstanden, als jemand mit der Frage auf mich zukam, ob man nicht einen einfachen Webseiten-Counter bauen könnte. Meine Gegenfrage, wofür die Welt noch eines dieser unnützen Spielzeuge braucht, wurde damit beantwortet, daß er nur einen Counter haben will, ohne von einem Service abhängig zu sein. OK, dann ginge es nicht vielleicht auch ohne? Nein, die Dinger zeigen, daß man beliebt ist … naja, oder auch nicht.
An sich gibt es immer viel zu tun und ich muß nicht unbedingt etwas suchen, an dem ich arbeiten muß. Obwohl … wie kann man so etwas mal eben schnell und trotzdem stabil bauen? Üblicherweise besteht so ein Counter aus einer Grafik und einer Datei bzw. Datenbank-Tabelle, die die Zugriffe speichert. Naja, das gibt’s aber auch schon geschätzte 1000mal. Aber Fotos von Digitalkameras speichern einige zusätzliche Daten direkt in den Fotos ab. Das läßt sich nutzen, wenn PHP direkten Zugriff darauf hat.
Also bauen wir zuerst die Logik für den Datenblock (IPTC-Block), der in einem JPG eingebettet werden soll, das später als Counter-Grafik fungieren wird. Erfreulicherweise stellt PHP dafür 2 Funktionen zu Verfügung: iptcparse () und iptcembed (). Das diese bisher noch nicht besonders umfangreich dokumentiert sind, soll uns nicht stören. Es gibt einige Beispiele beim php.net.
var $file;
function phpIptcTags ($file) {
if (is_file ($file)) {
$this->file = $file;
return ($this);
}
return (FALSE);
}
function read ($tag = null) {
if (is_readable ($this->file)) {
GetImageSize ($this->file, &$info);
if (isset ($info["APP13"])) {
$this->iptc = iptcparse ($info["APP13"]);
}
}
return (!is_null ($tag) ? $this->iptc["2#" . $tag][0]:$this->iptc);
}
function set ($tag, $input) {
if (!empty ($tag) && !empty($input) && isset ($this->iptc)) {
$this->iptc["2#" . $tag][0] = $input;
}
}
function write () {
if (isset ($this->iptc) && is_writable ($this->file)) {
$tags = ”;
foreach (array_keys ($this->iptc) as $s){
$tags .= $this->tag (2, str_replace ("2#", "", $s), $this->iptc[$s][0]);
}
$content = iptcembed ($tags, $this->file, 0);
$fp = fopen ($this->file, "w");
fwrite ($fp, $content);
fclose ($fp);
}
}
// Function to format the new IPTC text, (thanks to Thies C. Arntzen)
function tag ($rec, $dat, $val) {
$len = strlen ($val);
if ($len < 0×8000) {
return (
chr (0x1c).chr($rec).chr($dat) .
chr ($len >> 8 ) .
chr ($len & 0xff) .
$val
);
}
return (
chr (0x1c).chr($rec).chr($dat) .
chr (0×80).chr(0×04) .
chr (($len >> 24) & 0xff) .
chr (($len >> 16) & 0xff) .
chr (($len >> 8 ) & 0xff) .
chr (($len ) & 0xff).
$val
);
}
}
Damit wäre schon einmal dieser Teil erledigt. Wir haben eine Klasse für die Aufgabe, die IPTC-Tags zu lesen und zu schreiben. Der Konstrukter übernimmt als Parameter einen Dateiamen. Für alles weitere haben wir die Methoden read, set und write … die Funktion tag () habe ich mir in den Beispielen im php.net “geborgt”. Jetzt noch die Logik, die die Grafik malt. Nun, ich seh’ mich nicht gerade als Künstler im grafischen Bereich. Also fangen ich erst einmal gaaanz einfach an:
var $file;
var $background = ’000000′;
var $color = ‘FFFFFF’;
var $width;
var $height = 20;
function phpIPTC ($arr = array ()) {
$this->set ($arr);
}
function set ($arr) {
if (is_array ($arr) && !empty ($arr)) {
foreach ($arr as $key => $value) {
if (in_array ($key, array_keys (get_class_vars (get_class ($this))))) {
$this->$key = $arr[$key];
}
}
}
}
function makeImage ($input) {
if (is_writable ($this->file)) {
$im = imagecreatetruecolor (!empty ($this->width) ? $this->width : (strlen ($input) * 8 ) + 4, $this->height);
imagefill ($im, 0, 0, $this->allocateFromHex ($im, $this->background));
if (!is_null ($input)) {
imagestring ($im, 4, 2, 2, $input, $this->allocateFromHex ($im, $this->color));
}
imagejpeg ($im, $this->file, 80);
imagedestroy ($im);
}
}
function allocateFromHex ($im, $hexstr) {
$int = hexdec ($hexstr);
return (imagecolorallocate ($im, 0xFF & ($int >> 0×10), 0xFF & ($int >> 0×8), 0xFF & $int));
}
}
Die Klasse ist erst einmal abstrakt genug, um auch in den noch folgenden Teilen dieser Serie zu arbeiten. Was noch fehlt, ist die entsprechende Spezialisierung für unseren Counter:
var $value;
function get () {
$iptc = new phpIptcTags ($this->file);
$this->value = $iptc->read (120) + 1;
$this->makeImage ($this->width * $this->height == 1 ? null:$this->value);
$iptc->set (120, $this->value);
$iptc->write ();
return ($this->file);
}
}
Hierzu sollte ich vielleicht noch etwas anmerken. phpIPTCCounter ist ein abgeleitete Klasse und benutzt, da sie selbst über keinen Constructor verfügt, den der Eltern-Klasse. Somit läßt sich beim Konstruieren des Objekts der Dateiname übergeben. Die Methode get () erledigt die eigentlich Arbeit. Sie speichert in $value den eventuell schon gesetzten Wert und inkrementiert ihn. Danach wird das Image neu erstellt, um die Zahl auf den Counter zu schreiben. Wurde als Größe 1 x 1 angegeben, wird ein sogenanntes Zählpixel ohne Beschriftung erstellt. Danach wird der neue Wert aus $value in die Grafik eingebettet und der Dateiname wird zurückgegeben.
Der komlette Code mit Anwendungsbeispiel zum downloaden!
Have fun!