RSS Atom New Article

Monitoring Puppet with Munin

Just recently we had some hickups in our puppet infrastructure.

The question we were facing afterwards was, if all the nodes are regularily getting their updates. The specific problem is, that the infrastructure of the puppet and svn system is maintained by another department and so we don't have access to their exact monitoring data.

So the idea was to write a munin plugin, that will alarm me, when one or many hosts are late for their updates.

This would be trivial. I wanted a special solution. I wanted the plugin itself, not only configured by the puppet, but I wanted it to be completely generated by puppet.

There is a puppet-module Concat which allows to build Textfiles from Fragments.

So My idea was, to generate a Plugin completely from fragments that are generated on all the puppetnodes themselfes. And Thats what I did: Put the following receipt into the manifest for the host, where the plugin should be shown:

    concat { "/usr/local/share/munin/plugins/puppetlastrun":
        owner => 'munin',
        group => 'munin',
        mode => '755',
        notify => Service["munin-node"],
        }
    concat::fragment {"/usr/local/share/munin/plugins/puppetlastrun.header1":
        target     => "/usr/local/share/munin/plugins/puppetlastrun",
        order => 04,
        content =>
"#!/bin/bash
#
# Generated by Puppet:
# $Revision
#
#
if [ \"\$1\" = \"config\" ]; 
    then
        echo 'graph_title Puppetrun-Ages'
        echo 'graph_args --base 1000 -l 0 '
        echo 'graph_category Updates'
        echo 'graph_info This graph shows age of last puppetrun'
        echo 'runtime.label last runtimes'
"
        }

    concat::fragment {"/usr/local/share/munin/plugins/puppetlastrun.header2":
        target     => "/usr/local/share/munin/plugins/puppetlastrun",
        order => 06,
        content =>
'               exit 0
    fi
'
        }

    concat::fragment {"/usr/local/share/munin/plugins/puppetlastrun.work8":
        target     => "/usr/local/share/munin/plugins/puppetlastrun",
        order => 28,
        content =>
'
exit 0
'
        }

    Concat::Fragment <<| (tag == 'muninplugin_puppetruntimes') |>>

    file {"/usr/share/munin/plugins/puppetlastrun":
        ensure => link,
        target => "/usr/local/share/munin/plugins/puppetlastrun",
        require => File["/usr/local/share/munin/plugins/puppetlastrun"]
        }

This will generate a skeleton of the munin-plugin on the munin-node, thats monitoring. You can spot the Concat::Fragment <<||>> - which gathers external resources. These will be fillled by the nodes themselfes. Now we need to fill the plugin with data, that every node has to supply.

Put the following receipt into each puppetnodes manifest:

@@concat::fragment {"/usr/local/share/munin/plugins/puppetlastrun.header.$hostname":
    target   => "/usr/local/share/munin/plugins/puppetlastrun",
    tag => [ "${hostname}","muninplugin_puppetruntimes","$environment"],
    order => 05,
    content =>
"
            echo \"runtime_$hostname.label runtime_$hostname\"
            echo \"runtime_$hostname.draw AREASTACK\"
            echo \"runtime_$hostname.info $hostname \"
            echo \"runtime_$hostname.warning 28800\"  # 8 hours
            echo \"runtime_$hostname.critical 86400\"  # 24 hours
"
    }
@@concat::fragment {"/usr/local/share/munin/plugins/puppetlastrun.work.$hostname":
    target   => "/usr/local/share/munin/plugins/puppetlastrun",
    tag => [ "${hostname}","muninplugin_puppetruntimes","$environment"],
    order => 25,
    content =>inline_template(
"           echo runtime_$hostname.value \$(( \$(date +%s) - <%= Time.now.to_i %> ))  # Last Puppet run was <%= Time.now %>
"),
    }

This fills the munin-plugin once with the config-options for this host, and also generates the stuff neccessary to return the value to munin.

The interesting part is the line:

content =>inline_template("echo runtime_$hostname.value \$(( \$(date +%s) - <%= Time.now.to_i %> ))  # Last Puppet run was <%= Time.now %>")
  • First we're using inline_template() - this allows us to get the current timestamp, and embedd it into the returned string. Thats the part with <%= Time.now.to_i %>. This gives us the current timestamp in seconds since 1.1.1970.
  • this Timestamp gets embedded in an bash-command:
    • echo $(( )) allows us to do some small calculations on cmdline
    • $(date +%s) returns the time when called in the plugin
Posted on Di 09 Apr 2013 15:10:21 CEST Tags:

Keine Werbung!

Ich habe seit ein paar Wochen bei mir am Briefkasten einen Aufkleber angebracht.

Wenn ich mir anschaue, was der Inhalt der Papiermülltonnen, hergibt, dann sehe ich dort gefühlte 80% Werbung und ähnliches Zeug, welches direkt aus den Briefkästen dort hinein geflogen ist.

Und dafür zahle ICH Müllgebühren!

Dieser Artikel hier ist in dem QR-Code verlinkt, den man am rechten Rand des Aufklebers erkennt. (Zusätzlich steht in den kleinen Zeilen noch sinngemäß, dass ich die Werbung sowieso nicht lesen werde)

Hall-of-Fame

In der hier aufgestellten Hall-of-Fame werde ich nun zukünftig Werbung für die Unternehmer verbreiten, deren Personal nicht des Lesens mächtig genug sind, oder trotzdem der Meinung sind, mir ihr Papier zustellen zu müssen.

Bist jetzt hat sich noch kein neuer Aspirant gefunden, der die HoF beginnen möchte...

Posted on Sa 14 Apr 2012 18:47:00 CEST Tags:

10 Facts about Introverts

Myth #1 – Introverts don’t like to talk.

This is not true. Introverts just don’t talk unless they have something to say. They hate small talk. Get an introvert talking about something they are interested in, and they won’t shut up for days.

Myth #2 – Introverts are shy.

Shyness has nothing to do with being an Introvert. Introverts are not necessarily afraid of people. What they need is a reason to interact. They don’t interact for the sake of interacting. If you want to talk to an Introvert, just start talking. Don’t worry about being polite.

Myth #3 – Introverts are rude.

Introverts often don’t see a reason for beating around the bush with social pleasantries. They want everyone to just be real and honest. Unfortunately, this is not acceptable in most settings, so Introverts can feel a lot of pressure to fit in, which they find exhausting.

Myth #4 – Introverts don’t like people.

On the contrary, Introverts intensely value the few friends they have. They can count their close friends on one hand. If you are lucky enough for an introvert to consider you a friend, you probably have a loyal ally for life. Once you have earned their respect as being a person of substance, you’re in.

Myth #5 – Introverts don’t like to go out in public.

Nonsense. Introverts just don’t like to go out in public FOR AS LONG. They also like to avoid the complications that are involved in public activities. They take in data and experiences very quickly, and as a result, don’t need to be there for long to “get it.” They’re ready to go home, recharge, and process it all. In fact, recharging is absolutely crucial for Introverts.

Myth #6 – Introverts always want to be alone.

Introverts are perfectly comfortable with their own thoughts. They think a lot. They daydream. They like to have problems to work on, puzzles to solve. But they can also get incredibly lonely if they don’t have anyone to share their discoveries with. They crave an authentic and sincere connection with ONE PERSON at a time.

Myth #7 – Introverts are weird.

Introverts are often individualists. They don’t follow the crowd. They’d prefer to be valued for their novel ways of living. They think for themselves and because of that, they often challenge the norm. They don’t make most decisions based on what is popular or trendy.

Myth #8 – Introverts are aloof nerds.

Introverts are people who primarily look inward, paying close attention to their thoughts and emotions. It’s not that they are incapable of paying attention to what is going on around them, it’s just that their inner world is much more stimulating and rewarding to them.

Myth #9 – Introverts don’t know how to relax and have fun.

Introverts typically relax at home or in nature, not in busy public places. Introverts are not thrill seekers and adrenaline junkies. If there is too much talking and noise going on, they shut down. Their brains are too sensitive to the neurotransmitter called Dopamine. Introverts and Extroverts have different dominant neuro-pathways. Just look it up.

Myth #10 – Introverts can fix themselves and become Extroverts.

Introverts cannot “fix themselves” and deserve respect for their natural temperament and contributions to the human race. In fact, one study (Silverman, 1986) showed that the percentage of Introverts increases with IQ.

Posted on Mo 02 Mai 2011 23:07:26 CEST Tags:

We are running out of IP Adresses

Are you ready for IPv6?

A nice video ... and its even from Cisco ...

Posted on Do 17 Feb 2011 13:09:45 CET Tags:

APNIC - IPv6 for the Kids

Posted on Fr 31 Dez 2010 11:08:44 CET Tags:

Commerzbank: Gehts noch?

Eigentlich bin ich ja seit fast 17 Jahren zufri^W Kunde bei der Dresdner Bank. Ich hatte mir im Alter von 14Jahren zusammen mit meinen Eltern damals ein "junges Konto" bei der Dresdner eröffnet (dieselbe Kontonummer, die ich noch immer führe). Glänzende Augen: "Mein eigenes Geldkonto" -- Mann-O-Mann war ich stolz ...

Eine "Geldkarte" gabs damals natuerlich noch nicht .. aber eine Plastikkarte , mit der ich am KAD meinen Kontostand abrufen konnte. Und: Ich hatte eine Kontonummer. Ich konnte am Bargeldlosen Geldverkehr teilnehmen.

Grosse Augen in der Schule als ich einem Kumpel die 3Wege-Boxen seiner Stereoanlage für 200Mark abkaufte, und ihm einen Scheck übergab. Wow - Toll!

--- Schnitt!

Die persönliche Trägheit führte dazu dass ich diesem Konto auch recht lange die Treue gehalten habe. Eine persönliche Betreuerin, die meinen Namen kennt, und bei der mit einem kurzen Anruf der überzogene Dispo auch erledigt ist. Selbst wenn die Kontoführende Stelle inzwischen 600km weg von meinem Wohnort liegt, überzeugt eine solche Kundenbindung, auch wenn die Konditionen anderswo besser sind. Selbst auf die Trennung zwischen "Giro-" und "Geldmarkt-"-Konto habe ich mich eingelassen, auch wenn dieses tolle "Produkt" das Leben wieder ein Stück umständlicher gemacht hat.

Egal: Persönliche Trägheit lenkt.

Aber, es gibt Impulse, die versetzen auch Schwere Ruhende Massen in Bewegung (rein physikalisch betrachtet).

Dass sich einiges ändern würde war bereits vor 5Jahren abzusehen, als die ersten bestätigten Gerüchte ueber eine Fusion zwischen Commerz- und Dresdner Bank die Runde machten.

Natürlich dauerte das Ganze noch geschlagene 4Jahre bis dann auch nach aussen hin zum Kunden tatsächlich eine Änderung zu spüren war (und damit meine ich nicht das neue Logo als Misch zwischen den beiden 'alten' Logos). Inzwischen scheint man der gesamten Dresdner Bank das Konzept der Commerzbank übergestülpt zu haben.

Bei der Dresdner habe ich nämlich damals, vor 5 Jahren, noch eine Kreditkarte beantragt. VISA sollte es sein. In den Jahren wurde ich auch schön promoviert .. immer schön ein Jahr lang die neue Karte (zB. ?SilberCard) und wenn man nicht kündigt oder widerspricht, hat man ein Jahr später die neue am Bein, die mehr kostet und auch mehr kann (was ich aber eh' nicht nutze und nicht brauch) ...

Egal: Persönliche Trägheit lenkt.

Was mich aber momentan ein wenig echauffiert, ist das folgende Ereignis.

Zum 28.10.2010 erhalte ich mal wieder Post von der Commerzbank. Da meine VISA bald (2011) abläuft! Und sowieso: Da Commerzbank nur noch Mastercard und nicht mehr VISA macht, stellt man gerade alle Desdner-Kunden um auf Mastercard. Hier wäre schonmal meine neue Mastercard. Die ist soweso besser weil Foo, Bar, Bla, Blubber ...

Hmmm, grübel: Ich habe noch nie ein Problem mit meiner VISA gehabt; Ich wüsste nicht, warum ich das ändern muesste.

Egal: Trägheit lenkt.

Der Brief mit der noch aufgeklebten neuen MC liegt am Samstag neben mir auf dem Tisch, als ich durch die Post schaue, in der auch die diesmonatlichen CC-Rechnungen stecken. -- Moment: Rechnunge*N* ??? Wieso sind da ZWEI Rechnungen? Hmmm -- Die sind beide fuer den selben Zeitraum? ACK!

Aber -- Die eine ist fuer die Mastercard!

Zwei Posten! Die Mastercard, die ich mit Schreiben vom 28.10. an mich rausging, hat ZWEI Posten vom 14.10. und vom 17.10. auf der Abrechnung! WTF!!!

Natürlicher Instinkt: Anruf bei der Telefonnummer rechts oben auf dem Brief -- Der "CardService". Unter diesen Umständen habe ich kein Problem damit eine 01805-Nummer anzurufen.

Erstmal mus ich natürlich das Nummernspiel durchspielen("Drücken sie 1 wenn Sie nicht wissen was sie tun wollen, Drücken Sie 2 wenn sie ...") , bevor ich zum humanoiden Endgegner durch komme -- Kein Problem.

Aber: Nachdem ich die Geschichte geschildert habe, (Der Kollege wollte noch nicht einmal Kontonummer, CC-Nummer, Rechnungsnummer oder irgendwas) wusste er schon Bescheid.

Er erklaerte mir: Die Commerzbank würde ja ALLE alten Dresdner-Bank-Kunden umstellen müssen von VISA auf MC. Und um zu sehen, ob alle Daten korrekt verknüpft sind, habe man TESTWEISE einzelne Posten von der VISA auf die MC umgebucht.

* BITTE WIE??? *

Das muss man sich mal auf der Zunge zergehen lassen? Da werden interne Umstellungs-Tests, (denen ich noch nicht zugestimmt habe und auch nicht vorher informiert wurde) mit Live-Daten gemacht, um zu schauen ob alles passt? (Was wäre denn eigentlich gewesen, wenns nicht gepasst haette?) Man nimmt dabei in Kauf zwei offensichtlich falsche Rechnungen an den Kunden zu schicken. Böse Köpfe könnten dahergehen und mir u.U. eine Verschleierung von Geschäftsvorgängen vorwerfen. Ich habe zwei Rechnungen in der Hand, auf der einen "fehlen" zwei Posten und auf der anderen Rechnung steht dass ich mit der Mastercard, die noch auf ihrem Brief klebt, die am 28.10. verschickt worden ist, bereits zwei Wochen vor Versendung der Karte 2 Buchungen getätigt habe.

Dies werde ich natürlich zurückbuchen lassen, und als solches anfechten.

Ich bin kein Jurist, und habe diesbzgl. keine haltbare Position, aber der Gedanke, dass dies kein "Abrechnungsversehen" ist, sondern eine gezielte und bewusste Veränderung der Datensätze bei der man offensichtlich falsche Rechnungen billigend inkaufnimmt, laesst bei mir im Hinterkopf die Urkundenfälschungsklingel laeuten. Die Hupe fuer Datenmanipulation röhrt auch schon. Aber das soll ein Jurist entscheiden.

Ein brisanter Punkt an der Geschichte ist natürlich die Auftragsdatenverarbeitung.

VISA und MC sind unterschiedliche Unternehmen mit eigenen Datenverarbeitern, die mit den Personenbezogenen Daten hantieren. Ich habe ausschliesslich mit der Dresdnerbank eine Vereinbarung, dass sie meine Daten an die VISA und deren Datenverarbeiter ausliefern darf. Die Commerzbank mag die Dresdner übernommen haben (auch wenn man das Fusion nennt) und damit auch meine Erlaubnis dass meine Daten an die VISA-Datenverarbeiter gegeben werden dürfen -- aber ich habe nirgends bewusst unterschrieben, dass meine Daten bei Mastercard landen dürfen. Vielleicht habe ich deswegen ja auch noch nicht mit der MC bezahlt. Jetzt erlangt die MC aber doch Datensätze zu meiner Person? -- HALLO???!?!

Ich werde das ganze jetzt mal ein wenig verfolgen:

  • Die Rechnung wird zurück gebucht.
  • Eine Stellungnahme Aufgrund welcher Vereinbarungen derartiges Verhalten erklärt werden kann wird von der Bank angefordert
  • Der Verbraucherschutz wird von mir angefragt.
  • Eine Anfrage an den Landesdatenschutz wird gestellt.
  • Ich werde das ganze juristisch untersuchen lassen.
  • Eine Anfrage sowohl nach dem öffentlichen Verfahrensverzeichnis der Bank, als auch dem konkreten Verfahrensverzeichnis nachdem meine Daten in diesem Fall behandelt wurden wird wohl auch gestellt werden müssen, genauso wie die Aufstellung an welche weiteren Dienstleister sie meine Daten weitergegeben haben ...

Es gibt Momente, da lenkt die Trägheit nicht mehr.

Objektiv fehlen mir die Argumente dieses Konto weiterzuführen. Andere Banken sind genauso schlecht, kosten mich weniger.

Ich werde mal schauen, wie sich die Bank rechtfertigt, und hier weiter berichten.

JEDENFALLS BIN ICH GERADE STINK-SAUER!

Posted on Mo 22 Nov 2010 13:52:41 CET Tags:

Upgrading Ubuntu to version 10.04 LTS

I have one laptop here(mjolnir), that I'm using for my work. I installed them ~2years ago, with an Ubuntu system, because it simply worked. I tried debian, but it didn't support all the hardware.

I did an upgrade to 9.* once and it worked quite well. Ubuntu has an Dist-Upgrade-Application, that does all the stuff for you.

When Ubuntu 10 was released, I tried the same again, but because in the meantime I installed some 3rd-party Software, I couldn't upgrade the system without conflicts.

Because I didn't have the time to analyze these, I postponed the upgrade.

Today I started it again, and I found out, which Applications issued the conflicts. I removed them and now the upgrade is running. ~3h still left

Posted on Di 26 Okt 2010 18:19:16 CEST Tags:

What would happen, if programmers wrote songlyrics?

Found via kaFux

http://songsincodedb.com/

if tonight in jungle ; then
    lion.sleep;
end

oder

 if ( !woman ) { cry = false; }

... oder auch:

foreach(person in Persons.getAll()){person.setDomicile(yellowSubmarine);}
Posted on So 25 Jul 2010 18:54:50 CEST Tags:

About Motivation

via Kris

Posted on Fr 23 Jul 2010 14:17:47 CEST Tags:

Deep Linking images from foreign domains

Last week I found in my webstatistics, that I had some spike in the traffic.

A foreign weblog or forum in hungarian language had one of the pictures on my site linked directly into their comments.

I have no Problems with people using my pictures on their Website, even less if its not a workfrom me, but from someone else, and I also only have a copy.

But what buggs me, is that other ones are reading forums and are seeing images on a foreign website and noone notices, that the image is delivered from my webserver, while on the other hand, my connection is filled up with 3000 requests in 2hours.

The theory

To limit this behaviour for the next time, I did some configuration of the webserver(lighttpd) and some php-scripting.

In future I'll decide for every request to an image if the referrer is either empty or from my website (at least lzer.net). If thats the case, then normally either someone is reading my site, or he got a direct link to an article or an image. Thats fine with me. But if an image is embedded from another website, then the browser must have send (at least in 95% of the cases, geeks don't count) an referrer thats completely different.

In this case I'll be redirecting them to another version of the image that will have the prefix '/img/cached' in front of the original image path.

The Webserver

Here is the part of the lighty-config reliable for that:

$HTTP["url"] =~ "^/wiki/blog/.*\.(gif|png|jpg|jpeg)$" {
    $HTTP["referer"] !~ "^($|http://.*\.?lzer\.net)" {
        url.redirect += ( "^/(.*)$" => "/img/cached/$1"  )
        accesslog.filename = "/var/log/lighttpd/suspected_imagetheft.log"
        }
    }

These images will contain a low-quality version of the original image, and have a text written over the complete image, that the image is linked from my site, and the author should rather copy the image to his site, instead of burning my bandwidth for nothing.

The funny part is, that normally these images don't exist, before they are requested the first time. They are created by an script that is run on the 404-Handler for this directory:

$HTTP["url"] =~ "^/img/cached/" {
        server.error-handler-404 = "/imagegenerator/"
        }

So what's happening there?

The Script

I had some time and fun with quick&dirty coding style. Following a commented version of "/imaggenerator/index.php":

<?php

$OriginalRequest=$_SERVER["REQUEST_URI"];

$URIParts=explode('/',$OriginalRequest);
list($EMPTY,$IMG,$CACHED,$RESTURI)=explode('/',$OriginalRequest);

First we're splitting the original request, and look, if we're really responsible. (Maybe someone directly called the script with a bad intention?)

if ( ('' == $EMPTY) and ('img' == $IMG)  and ('cached' == $CACHED) ) {

If that's fine, then we're splitting the request and build up the filenames of the original file to load and where the new file will go to

$I=3;
$RealImgFN='/var/www';
$NewImgFN='/var/www/img/cached';
$NewImgDir='/var/www/img/cached';
while($URIParts[$I]!='' ) {
    $RealImgFN.='/'.$URIParts[$I];
    $NewImgFN.='/'.$URIParts[$I];
    if (  !(($NewImgFN[strlen($NewImgFN)-4] == '.' ) or ($NewImgFN[strlen($NewImgFN)-5] == '.' )))  { $NewImgDir.='/'.$URIParts[$I]; }      
    $I++;
    }

If we have that, we check for the filetype and load the file for the first time.

switch(strtolower(substr($RealImgFN,-4,4))) {
        case ".jpg" : 
            $im     = imagecreatefromjpeg($RealImgFN);
            break;
        case ".png" : 
            $im     = imagecreatefrompng($RealImgFN);
            imagesavealpha($im,true);
            $is_png=true;
            break;
        case ".gif" : 
            var_dump("GIF");
            $im     = imagecreatefromgif($RealImgFN);
            break;
    }       
if (strtolower(substr($RealImgFN,-5,5))==".jpeg") {
    $im= imagecreatefromjpeg($RealImgFN);
    }

If it's an PNG-File, we remember that. At least we should now have "$im" loaded. If thats not the case, then we redirect to a generic image (look down)

if ($im) {
        @mkdir($NewImgDir,0777,true);           

Why mode 0777 ? Because the umask will take care of the maximal rights on my webserver. You would have to check for that yourself. if (!is_png) { imagejpeg($im,$NewImgFN.".tmp.jpg",5); $im=imagecreatefromjpeg($NewImgFN.".tmp.jpg"); }

But here's the fun part: If it's not an PNG (Which will probably have Alpha(Transparency)-Information in it, which get lost on JPEG-Compression) then we first write it out as an temp-image with JPEG-Compression 5 (Which is VERY LOW quality) and reopen it.

Then we prepare for the text to write into the image.

        $string1    = "Image linked to http://wa.lzer.net";
        $fontfile='/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf';
        $blue = imagecolorallocate($im, 64, 144, 255);
        $black = imagecolorexactalpha($im, 0, 0, 0,64);
        $red = imagecolorallocate($im, 224, 64, 32);
        $white = imagecolorexactalpha($im, 255, 255,255,64);

        $maxX=imagesx($im);
        $maxY=imagesy($im);

And here it becomes interesting:

I want to write 2 Lines diagonally over the image, in a good, readable size. This means I'll have to calculate the angle first, in which to write the text. As it happens, thats the arcustangens of the image dimensions.

        $ratio=$maxX/$maxY;
        $mean=atan2($maxY,$maxX);
        $ang=rad2deg($mean);

Then I need to find out, which fontsize to select, so that its still readable. I increase the fontsize by one and look of the size of the boundingbox of the text:

        $bbx=1;$bby=1;$fs=1;
        while ((abs(($maxX/$bbx)*($maxY/$bby))>3) or (fs>120)) {            
            $fs+=1;
            $BBox=imagettfbbox($fs,$ang,$fontfile,$string1);
            $bbx=$BBox[4]-$BBox[0];
            $bby=$BBox[5]-$BBox[1];
            $e=abs(($maxX/$bbx)*($maxY/$bby));
            }

Because I write two lines, I'm moving the text a bit away from the diagonale

        $px=($maxX-$bbx)/2- (1*sin(deg2rad($ang))*$fs);
        $py=($maxY-$bby)/2- (1*cos(deg2rad($ang))*$fs);
        $ts=$fs;

I told you, it's quick 'n dirty, didn't I? So for the second Textline I store the main variables away, and do the position calculation again.

        $BBox1=$BBox;
        $px1=$px;
        $py1=$py;
        $ts1=$ts;

        $string="to the Author: Please copy the original to your site!";
        $fs*=0.6;
        $BBox=imagettfbbox($fs,$ang,$fontfile,$string);
        $bbx=$BBox[4]-$BBox[0];
        $bby=$BBox[5]-$BBox[1];
        $px=($maxX-$bbx)/2+ (2*sin(deg2rad($ang))*$fs);
        $py=($maxY-$bby)/2+ (2*cos(deg2rad($ang))*$fs);
        $ts=$fs;

Now comes another funny part:

Because Sometimes the text is hard to read on colored Images, I wanted the background of the text come grey. I'm trying to create a gradient of the boundingbox of the text to the outside of the image. It's ugly code, I dare to comment ...

        $points=array (
                        $px+$BBox[6] , $py+$BBox[7],
                        $px+$BBox[0] , $py+$BBox[1],
                        $px+$BBox[2] , $py+$BBox[3],
                        $px+$BBox[4] , $py+$BBox[5],
                        $px1+$BBox1[2],$py1+$BBox1[3],
                        $px1+$BBox1[4],$py1+$BBox1[5],
                        $px1+$BBox1[6],$py1+$BBox1[7],
                        $px1+$BBox1[0],$py1+$BBox1[1]
                );

        $p1dx=0*imagesx($im);$p1dy=1*imagesy($im);
        $p2dx=0*imagesx($im); $p2dy=1*imagesy($im);
        $p3dx=1*imagesx($im); $p3dy=1*imagesy($im);
        $p4dx=1*imagesx($im); $p4dy=0.5*imagesy($im);
        $p5dx=1*imagesx($im); $p5dy=0.5*imagesy($im);
        $p6dx=1*imagesx($im); $p6dy=0*imagesy($im);
        $p7dx=0*imagesx($im); $p7dy=0*imagesy($im);
        $p8dx=0*imagesx($im); $p8dy=0.5*imagesy($im);

        $AlphaGrey=imagecolorexactalpha($im,127,127,127,96);

        $delta=(
                abs($p1dx-$points[0])+abs($p1dy-$points[1])+
                abs($p2dx-$points[2])+abs($p2dy-$points[3])+
                abs($p3dx-$points[4])+abs($p3dy-$points[5])+
                abs($p4dx-$points[6])+abs($p4dy-$points[7])+
                abs($p5dx-$points[8])+abs($p5dy-$points[9])+
                abs($p6dx-$points[10])+abs($p6dy-$points[11])+
                abs($p7dx-$points[12])+abs($p7dy-$points[13])+
                abs($p8dx-$points[14])+abs($p8dy-$points[15])
            );

        $f=0.75;
        $c=0;
        while (($delta>128) and ($c++ < 200))
            {
            imagefilledpolygon($im,$points,8,$AlphaGrey);

            $points[0]=(($points[0]*$f)+((1-$f)*$p1dx));$points[1]=(($points[1]*$f)+((1-$f)*$p1dy));
            $points[2]=(($points[2]*$f)+((1-$f)*$p2dx));$points[3]=(($points[3]*$f)+((1-$f)*$p2dy));
            $points[4]=(($points[4]*$f)+((1-$f)*$p3dx));$points[5]=(($points[5]*$f)+((1-$f)*$p3dy));
            $points[6]=(($points[6]*$f)+((1-$f)*$p4dx));$points[7]=(($points[7]*$f)+((1-$f)*$p4dy));
            $points[8]=(($points[8]*$f)+((1-$f)*$p5dx));$points[9]=(($points[9]*$f)+((1-$f)*$p5dy));
            $points[10]=(($points[10]*$f)+((1-$f)*$p6dx));$points[11]=(($points[11]*$f)+((1-$f)*$p6dy));
            $points[12]=(($points[12]*$f)+((1-$f)*$p7dx));$points[13]=(($points[13]*$f)+((1-$f)*$p7dy));
            $points[14]=(($points[14]*$f)+((1-$f)*$p8dx));$points[15]=(($points[15]*$f)+((1-$f)*$p8dy));

            $delta=(
                    abs($p1dx-$points[0])+abs($p1dy-$points[1])+
                    abs($p2dx-$points[2])+abs($p2dy-$points[3])+
                    abs($p3dx-$points[4])+abs($p3dy-$points[5])+
                    abs($p4dx-$points[6])+abs($p4dy-$points[7])+
                    abs($p5dx-$points[8])+abs($p5dy-$points[9])+
                    abs($p6dx-$points[10])+abs($p6dy-$points[11])+
                    abs($p7dx-$points[12])+abs($p7dy-$points[13])+
                    abs($p8dx-$points[14])+abs($p8dy-$points[15])
                );
            }

But when that's ready, then we finally write the text itself. Having an positive offset in white and an negative offset in black gives an additional effect, and should make it even more readable.

        imagefttext($im,$ts1,$ang,$px1-1,$py1-1,$white,$fontfile,$string1);
        imagefttext($im,$ts1,$ang,$px1-0,$py1-1,$white,$fontfile,$string1);
        imagefttext($im,$ts1,$ang,$px1-1,$py1-0,$white,$fontfile,$string1);
        imagefttext($im,$ts1,$ang,$px1-2,$py1-2,$white,$fontfile,$string1);
        imagefttext($im,$ts1,$ang,$px1+1,$py1+1,$black,$fontfile,$string1);
        imagefttext($im,$ts1,$ang,$px1+0,$py1+1,$black,$fontfile,$string1);
        imagefttext($im,$ts1,$ang,$px1+1,$py1+0,$black,$fontfile,$string1);
        imagefttext($im,$ts1,$ang,$px1+2,$py1+2,$black,$fontfile,$string1);
        imagefttext($im,$ts1,$ang,$px1,$py1,$blue,$fontfile,$string1);

        imagefttext($im,$ts,$ang,$px-1,$py-1,$white,$fontfile,$string);
        imagefttext($im,$ts,$ang,$px+1,$py+1,$black,$fontfile,$string);
        imagefttext($im,$ts,$ang,$px,$py,$red,$fontfile,$string);

Now the imagecontent is ready. We´re writing the image (PNG stays PNG). And after that, we redirect to the same location again.

        @mkdir($NewImgDir,0777,true);
        if ($is_png) {
            imagepng($im,$NewImgFN);
            } else {
            imagejpeg($im,$NewImgFN,50);                
            }
        imagedestroy($im);

But now' the requested Image should be in its place and get directly delivered. Otherwise it'll be recreated again.

        header("Location: $OriginalRequest");
    } else {
        header("Location: /img/cached/ImageTheft.png");
    }
}
?>

This script was hacked in two days and has enough potential to get optimized, but I was in the need of an quick solution. The this is, that the cached images are more compressed and therefore also spare me some bandwidth.

Posted on Do 17 Jun 2010 15:15:26 CEST Tags: