Anfang

Die "Schnipsel", die es hier zu finden gibt sind eine kunterbunte Mischung aus Code-Beispielen, weiterführenden Informationen und Hinweisen. Die Sammlung wird immer wieder erweitert, jedoch nicht zu festen Zeitpunkten, sondern meistens dann, wenn ich selbst etwas Neues brauche und zusätzlich die Zeit finde, es als Tutorial aufzubereiten.

Die Reihenfolge ist nicht inhaltlich festgelegt, sondern ergibt sich einfach aus dem Zeitpunkt der Veröffentlichung.

Viel Spaß damit!


Daten und Tabellen

Als weitergehende Information zu Daten ausgeben, hier eine kurze Erklärung, wie man Daten z. B. in einer Tabelle ausgeben kann. Wir gehen hier davon aus, dass wir bereits die Daten abgefragt und sie in der Variable $ergebnis gespeichert haben.

Wir brauchen jetzt die while-Schleife, in der die Daten über mysqli_fetch_object übernommen werden und die so lange ausgeführt wird, bis alle Daten aus der DB ausgelesen wurden.
<?php
... diverser Code ...
while($row = mysqli_fetch_object($ergebnis))
{
  echo $row->url;
  echo "<br />";
  echo $row->urlname;
  echo "<br /><br />";
}
?>
Das liefert zunächst einfach nur die Url und den Urlnamen zurück, allerdings mit Zeilenumbrüchen (<br />) voneinander getrennt, also so:

http://www.schattenbaum.net
Schattenbaum

http://www.htmling.net
HTMLing

usw.

Zwischen jedem Eintrag ist also ein Absatz, der dadurch entsteht, dass am Ende jedes Durchgangs der while-Schleife - also am Ende jedes Datensatzes - ein doppeltes <br /> verwendet wird.

Ganz ähnlich gehen wir jetzt vor, wenn die Daten in eine Tabelle geschrieben werden sollen. Dabei müssen wir zuerst überlegen, welcher Teil der Tabelle für jeden Datensatz wiederholt werden muss bzw. welcher für jede Datenzelle wiederholt werden muss.

Da wir nicht für jeden Datensatz eine extra Tabelle, sondern nur eine extra Reihe aufrufen wollen, muss der Aufruf der Tabelle außerhalb der while-Schleife stehen.
<?php
... diverser Code, Datenbank-Abfrage ...
 
echo "<table>";
while($row = mysqli_fetch_object($ergebnis))
{
  echo "<tr>";
  echo "<td>",$row->url,"</td>";
  echo "<td>",$row->urlname,"</td>";
  echo "</tr>";
}
echo "</table>";
?>
Jetzt wird alles in einer Tabelle ausgegeben, wobei für jeden Datensatz eine neue Tabellenzeile angelegt wird, weswegen die <tr> zwar innerhalb der while-Schleife stehen aber nur am Anfang und am Ende der Schleife aufgerufen werden, im Gegensatz zu den <td>, die bei jeder Ausgabe eines Feldes angewandt werden.

In dem Fall wurde der HTML-Code direkt über Echos ausgegeben, interessant ist dabei vielleicht das Schema "<td>",$row-url,"".

Die Textteile werden dabei in Anführungszeichen gesetzt und durch Komma von den Variablen (hier $row->url) getrennt.

Eine 2. Variante wäre es natürlich, den HTML-Teil außerhalb des PHP-Codes zu schreiben und dabei auf Teile der Echos zu verzichten:
<?php
... diverser Code, Datenbank-Abfrage ...
?>
<table>
<?php
while($row = mysqli_fetch_object($ergebnis))
{
  ?>
  <tr>
  <td>
  <?php
  echo $row->url;
  ?>
  </td>
  <td>
  <?php
  echo $row->urlname;
  ?>
  </td>
  </tr>
  <?php
}
?>
</table>
<?php
}
?>
Das ist jetzt ziemlich unübersichtlich, allerdings soll es auch nur die Möglichkeiten darstellen, die man hat. In der Praxis wird man in den meisten Fällen beide Varianten kombinieren und einen Teil außerhalb des PHP-Bereichs schreiben und den Rest per echo ausgeben.


PHP-Newsletter

Prinzipiell möchte ich von PHP-Newslettern abraten. Newsletter in PHP lassen sich zwar wunderbar programmieren (egal ob mit Textdatei oder Datenbank), haben aber auch Nachteile.

Prinzipiell gibt es zwei Möglichkeiten: Man schickt an jeden Empfänger eine extra Mail oder man schickt an alle zugleich, in dem man die Abonnenten als BCC (bitte nicht CC!) angibt. (Lässt sich über den Mailheader beeinflussen.)

Kreiert man für jeden User eine eigene Mail, hat das den Nachteil, dass immer wieder die Mailfunktion von neuem aufgerufen werden muss und dadurch der Server sehr viel mehr belastet wird.

Ein großes Problem haben aber beide Varianten. Ab etwa 1000 Abonnenten kann es passieren, dass nicht alle Mails versendet werden. Die Anzahl ist abhängig von der max_execution_time des Servers - der maximalen Ausführdauer eines Scripts. Wenn es zuviele Empfänger sind, das Script also zu lange ausgeführt werden müsste, dann wird es einfach abgebrochen und man hat Pech gehabt.

Ich habe nicht ausprobiert, wie viele Abonnenten wirklich funktionieren würden, sondern stütze mich dabei auf Informationen aus dem Netz. Man sollte aber immer überlegen, ob man nicht doch besser auf professionelle Methoden setzt.


Umfrage-Beispiel

Eine ganz simple Umfrage ist mit Hilfe von PHP und MySQL sehr leicht zu bewerkstelligen. Simpel vor allem deshalb, weil bei diesem Script die Möglichkeit besteht, dass ein User mehrfach abstimmt.

Zunächst brauchen wir ein Formular für die Abfrage:
<form action="abstimmen.php" method="post">
Welches Tier h&auml;ttest du gerne als Haustier?
<br /><br />
<input type="radio" name="Haustier" value="Katze"> Katze
<br />
<input type="radio" name="Haustier" value="Hund"> Hund
<br />
<input type="radio" name="Haustier" value="Nagetier"> Nagetier
<br />
<input type="radio" name="Haustier" value="Sonstiges"> Sonstiges
<br /><br />
<input type="submit" value="Absenden">
</form>
Wir bieten dem Benutzer also vier Möglichkeiten, sich zu entscheiden. Diese vier Möglichkeiten müssen wir beim Anlegen unserer Tabelle berücksichtigen, sie legen nämlich unsere Datensätze fest, das heißt, für jedes Tier wird ein Datensatz angelegt, bei dem in einer extra Spalte gezählt wird, wie oft das Tier schon ausgewählt wurde.

Damit ist auch schon klar, was für Spalten wir in unserer Tabelle brauchen: Eine für die Id, eine, die das Tier festlegt (könnte man aber auch über die Id regeln, wenn man möchte) und eine, in der gezählt wird.

Wir legen also über phpMyAdmin eine neue Tabelle mit dem Namen haustierwunsch an, die drei Felder bekommt: id, haustier und count. Das Feld id wird unser Primärschlüssel (primary key).

id - int - 1 - unsigned - not null - auto_incremt
haustier - varchar - 10
count - int - 10

Das auto_increment ist nicht unbedingt nötig, da wir ohnedies nur vier Datensätze haben werden, aber da wir direkt über phpMyAdmin die Datensätze angeben, ersparen wir uns ein wenig Arbeit dadurch.

Als nächstes müssen wir also unsere Datensätze in die Tabelle einfügen. Dafür wählen wir "Einfügen" und geben einfach in das Feld "Haustier" zunächst Katze ein. Die Felder id und count können wir so lassen, wie sie sind. Id deshalb, weil wir ja auto_increment gewählt hatten und sich die id damit selbst festlegt und das Feld count, weil es ein Feld vom Typ Integer ist und auf "NOT NULL" steht und damit automatisch den Standardwert 0 zugewiesen bekommt, wenn wir die Vorbelegung nicht ändern.

Wir legen jetzt noch drei weitere Datensätze für Hund, Nagetier und Sonstiges an und gehen dabei genauso vor.

Wenn man "anschließend eine neuen Datensatz einfügen" anwählt, muss man übrigens nicht jedes Mal neu auf Einfügen gehen.

Nachdem unsere Tabelle jetzt angelegt ist, können wir uns mit der Weiterverarbeitung unserer ausgewählten Haustiere befassen.

Dafür benötigen wir die Datei abstimmen.php auf die das Formular zielt. In dieser Datei nehmen wir zunächst die Daten aus dem Formular entgegen:
<?php
$haustier = $_POST["Haustier"];
?>
Wichtig ist hierbei, auf die richtige Schreibweise im Formular zu achten. Da wir dort als Formularnamen "Haustier" großgeschrieben verwendet haben, müssen wir darauf achten, es jetzt auch groß zu schreiben. Der Variablenname kann hingegen ruhig anders geschrieben sein - oder sogar ganz anders lauten. An dieser Stelle der Hinweis, dass hier keinerlei Sicherheitsüberprüfung der übergebenen Daten stattfindet. Mehr Informationen dazu, findest du bei Daniel Fett.

Als nächstes fragen wir in der Tabelle ab, wie oft denn das dieses Mal ausgewählte Haustier bisher bereits gewählt wurde:
<?php
$abfrage = mysqli_query($db, "SELECT * FROM haustierwunsch WHERE haustier = '$haustier'");
?>
Ich kombiniere in dem Fall die Abfrage gleich mit dem Abfragebefehl (mysqli_query), da diese Variante für mich übersichtlicher ist.

Da wir nur einen Datensatz zurückgeliefert bekommen können wir die while-Schleife sparen und den Datensatz direkt umschreiben lassen:
<?php
$datensatz = mysqli_fetch_object($abfrage);
$haustieranzahl = $datensatz->count;
?>
In der Variable haustieranzahl ist jetzt also gespeichert, wie oft das Haustier bereits ausgewählt wurde - in unserem Fall 0-mal, da wir ja vorher noch nicht gewählt haben.

Diese Anzahl wird jetzt um eins erhöht, um die Stimme dazu zu zählen, die eben gewählt hat.
<?php
$haustieranzahl++;
?>
Als nächstes muss diese Zahl in der Datenbank angepasst werden, dafür ändern wir den Datensatz:
<?php
$update = mysqli_query("UPDATE haustierwunsch Set count = '$haustieranzahl' WHERE haustier = '$haustier'");
?>
Damit der User bemerkt, dass seine Wahl auch wirklich angenommen wurde, geben wir jetzt noch ein Danke an ihn aus. Das kann entweder über den PHP-Befehl echo erfolgen, oder einfach außerhalb des PHP-Bereiches.
<?php
echo "Danke, dass du abgestimmt hast.";
?>
oder eben einfach nur
Danke, dass du abgestimmt hast.
Wenn wir jetzt die Datei mit dem Formular aufrufen, dort ein Haustier auswählen und dann durch einen Klick auf den Button die abstimmen.php aufrufen, sollte sich in der Datenbank die Anzahl beim gewünschten Haustier erhöht haben.

Man kann die Umfrage natürlich auch so umbauen, dass für jede Abstimmung ein eigener Datensatz angelegt wird, der auch das Haustier beinhaltet. Damit hat man dann auch die Möglichkeit, die IP-Adresse oder einen Benutzernamen mitzuloggen und somit jeden User nur einmal abstimmen zu lassen. Dadurch ändern sich aber auch die Abfragen.

Viel Spaß beim Ausprobieren, Umbauen und Anpassen.


Mehrere Daten einfügen

Nicht nur in den neueren phpMyAdmin-Versionen ist es möglich, mehrere neue Datensätze zugleich einzufügen, das selbe kann man natürlich auch selbst in seinem Code anwenden. Voraussetzung dafür ist, dass die selben Felder gefüllt werden sollen:
INSERT INTO tabellenname (feldname1, feldname2) VALUES ('abc', 'def'), ('ghi', 'jkl'), ('mno', 'pqr')
Die Werte für jeden Datensatz werden ganz normal in Klammern angeführt, die Datensätze per Komma getrennt.


Umfrage mit Grafik

Bei einer Präsentation von Umfrageergebnissen ist es wichtig, den Zuhörern die Diagramme anschaulich darzustellen. Vor der Präsentation müssen wir unsere Grafik allerdings erst einmal erstellen. Obwohl HTML 5 dafür eine schöne Option liefert, kann auch diese Methode eingesetzt werden. Im Folgenden führen wir das anhand der Ergebnisse der Beispiel-Umfrage durch und werten diese aus.

Da die Umfrageergebnisse grafisch dargestellt werden sollen, benötigen wir zunächst eine Grafik. Ich möchte im Endeffekt ein Balkendiagramm haben, das ungefähr so aussehen soll:

Katze 40 % 40 %
Hund 30 % 30 %
Nagetier 20 % 20 %
Sonstiges 10 % 10 %

Dabei reicht für die Balken eine 1 x 1 Pixel große, einfarbige Grafik aus - wir vergrößern sie danach einfach passend (bei einfarbigen Grafiken ist das problemlos möglich, wenn man einen Verlauf möchte, sollte man die Grundgrafik etwas größer machen).

Jetzt können wir uns daran machen, die Daten aus der mySQL-Datenbank abzufragen:
<?php
$abfrage = mysqli_query($db, "SELECT count FROM haustierwunsch WHERE id = '1'");
$ergebnis = mysqli_fetch_object($abfrage);
$katzenwunsch = $ergebnis->count;
?>
Wir fragen dabei jedes Tier einzeln ab und übertragen den Wert aus der Spalte count - also die Häufigkeit des Wunsches nach einem bestimmten Tier - gleich in eine Variable. Das machen wir jetzt nach dem gleichen Schema mit allen drei Möglichkeiten und speichern diese in die Variablen $hundewunsch, $nagerwunsch und $sonstigerwunsch.

Eine schönere Variante ist, das ganze über variable Variablen zu lösen - allerdings ist dieser Weg für Anfänger auch schwerer verständlich, weswegen ich das jetzt nicht erkläre. Also bitte keine Angst bekommen.

Jetzt benötigen wir nur ein wenig Mathematik, da wir die einzelnen Zahlen in Prozentsätze umrechnen müssen. Dafür addieren wir zunächst alle Ergebniszahlen und berechnen danach die einzelnen Prozentwert:
<?php
$gesamt = $katzenwunsch + $hundewunsch + $nagerwunsch + $sonstigerwunsch;
$katzenprozent = $katzenwunsch * 100 / $gesamt;
$hundeprozent = $hundewunsch * 100 / $gesamt;
$nagerprozent = $nagerwunsch * 100 / $gesamt;
$sonstprozent = $sonstigerwunsch * 100 / $gesamt;
?>
Mit Hilfe der Prozentsätze wird jetzt die Breite des Balken, also der Grafik bestimmt. Wollen wir z. B., dass der Balken maximal 300 Pixel breit sein darf, wenn ein Wert 100 % hat, so ist jeder Prozentpunkt 3 Pixel breit (maximale Breite / 100). Dieses Wissen können wir dann verwenden, um zu berechnen, wie breit z. B. 20 % wären (Breite eines Prozents * Prozent).
<?php
$katzenbalken = $katzenprozent * 3;
$hundebalken = $hundeprozent * 3;
$nagerbalken = $nagerprozent * 3;
$sonstbalken = $sonstprozent * 3;
?>
Und jetzt müssen wir diese ganzen Berechnungen nur noch anzeigen lassen, z. B. in einer Tabelle:
<table>
  <tr>
    <td>Katzen</td>
    <td><img src="balken.gif" width="<?php echo $katzenbalken; ?>" height="10" alt="<?php echo $katzenprozent; ?> %" /></td>
    <td><?php echo $katzenprozent; ?> %</td>
  </tr>
  <tr>
    <td>Hunde</td>
    <td><img src="balken.gif" width="<?php echo $hundebalken; ?>" height="10" alt="<?php echo $hundeprozent; ?> %" /></td>
    <td><?php echo $hundeprozent; ?> %</td>
    </tr>
  <tr>
    <td>Nager</td>
    <td><img src="balken.gif" width="<?php echo $nagerbalken; ?>" height="10" alt="<?php echo $nagerprozent; ?> %" /></td>
    <td><?php echo $nagerprozent; ?> %</td>
  </tr>
  <tr>
    <td>Sonstiges</td>
    <td><img src="balken.gif" width="<?php echo $sonstbalken; ?>" height="10" alt="<?php echo $sonstprozent; ?> %" /></td>
    <td><?php echo $sonstprozent; ?> %</td>
  </tr>
</table>



Variable Variablen

Variable Variablen haben einen Variablennamen, der aus einer Variable besteht:
$wetter = "regen";
$$wetter = "Das ist eine variable Variable.";
In dem Fall enthält also die Variable $wetter den Wert regen und damit ist der Name der variablen Variable $regen, da er aus dem Inhalt der Variable $wetter besteht.

Erkennbar sind sie an den doppelten Dollarzeichen, die dadurch entstehen, dass eine Variable ein Dollarzeichen braucht (das erste) und dass der Name aus einer anderen Variable besteht, die natürlich ihr eigenes Dollarzeichen mitbringt (das zweite).

Wir hätten diese Variablenvariante z. B. bei der Auswertung der Umfrage einsetzen können, indem wir eine einzige Abfrage über die gesamte Tabelle gemacht hätten, anstatt jedes Tier extra abzufragen, und dabei variable Variablen verwenden können, um dennoch für jedes Tier eine eigene Variable zu haben.
<?php
$abfrage = mysqli_query($db, "SELECT * FROM haustierwunsch");
while($row = mysqli_fetch_object($abfrage))
{
  $tier = $row->haustier;
  $$tier = $row->count;
}
?>
Im ersten Durchlauf bekommt die Variable $tier den Wert "Katze", da das im ersten Datensatz im Feld haustier steht. Dadurch ist der tatsächliche Name der variablen Variable dann $Katze und sie bekommt gleich den Wert aus dem Feld count des selben Datensatzes zugewiesen - die Häufigkeit des Katzenwunsches also.

Im zweiten Durchlauf bekommt die Variable $tier dann den Wert "Hund" aus der Datenbank und damit haben wir eine zweite Variable durch die variable Variable. Jetzt heißt sie $Hund und enthält die Häufigkeit des Hundewunsches, da wir ja gerade mit dem zweiten Datensatz beschäftigt sind.

Das selbe passiert auch bei den folgenden Durchläufen der while-Schleife für jeweils einen Datensatz aus der Datenbank und somit entsteht für jeden Datensatz eine eigene Variable, die sich aus der variablen Variable bildet und den dazu gehörigen count-Wert beinhaltet.

Damit wäre nach dem letzten Durchlauf der Schleife die Anzahl der einzelnen Tierwünsche in den Variablen $Katze, $Hund, $Nagetier und $Sonstiges gespeichert.

Nicht verzweifeln, wenn das auf den ersten Blick total verwirrend wirkt, sondern einfach langsam durch überlegen, dann ist das kein Problem.


mktime Probleme

Vor ein paar Jahren habe ich ein Adventskalenderscript erstellt, bei dem das Datum des jeweiligen Tages mittels mktime in einen Timestamp umgewandelt wurde, um zu überprüfen, ob das "Fenster" schon aufgehen darf.

mktime sah also für den 20.12.2002 z. B. so aus:
$akt_timestamp = mktime(0,0,0,12,20,2002);
Später hat ein Bekannter eine Art Adventskalender für jeden Monat daraus gemacht, und dafür das Script angepasst. Dabei hat er den Wert für den Monat zweistellig angegeben, also so:
$akt_timestamp = mktime(0,0,0,04,12,2003);
Das Script funktionierte problemlos, bis es dann Oktober wurde und als Monat 08 angegeben wurde. Da wurde mit einem Mal mit einem ganz falschen Datum gearbeitet.

Nach einiger Recherche kam ich dann darauf, dass dies daran liegt, dass diese Werte, wenn sie mit einer führenden Null angegeben werden, als Oktalzahlen interpretiert werden.

Somit wird 07 zwar als 7 interpretiert, bei 08 und 09 entstehen aber falsche Zahlen und somit funktionierte natürlich in diesen Monaten nichts mehr.

Daher bei mktime Werte immer ohne führende Null angeben!


Osterdatum

PHP hat übrigens einige sehr nette Kalenderfunktionen, bei denen man unter anderem ganz einfach den Ostersonntag ausgeben lassen kann.
$ostern = easter_date(<? echo date("Y"); ?>);
In der Klammer wird das gewünschte Jahr angegeben, der Rückgabewert ist ein Timestamp, der noch mit date formatiert werden kann.

So liefert also easter_date für 2024 z. B. den 30.03.2024 - der Code dafür sieht dann so aus:
<?php
echo date("d.m.Y",easter_date(date("Y")));
?>
Das sieht erstmal unheimlich kompliziert aus, um es zu erklären fangen wir am besten mit der letzten Funktion an. Das wäre date("Y"). Damit rufen wir die Datumsfunktion auf, und lassen uns über "Y" das aktuelle Jahr als vierstelligen Wert liefern. In unserem Fall also 2024.

Wenn wir jetzt eine Funktion weiter zurück gehen, sehen wir den Aufruf der easter_date-Funktion. Diese wird mit unserem Jahr gefüttert - wenn wir das also direkt schreiben wollten, würde da stehen easter_date(2024). Dieses Ergebnis ist allerdings nur ein Timestamp (1711839600) und daher übergeben wir ihn als Wert wiederum an die date-Funktion, damit das Osterdatum auch noch hübsch formatiert wird.

Wenn wir das in verschiedene Variablen schreiben würden, anstatt alles in einer Anweisung zu machen, würde das so aussehen:
<?php
$aktuelles_jahr = date("Y");
$ostern_timestamp = easter_date($aktuelles_jahr);
$ostersonntag = date("d.m.Y",$ostern_timestamp);
?>
Beide Varianten liefern das gleiche Ergebnis - die erste ist etwas unübersichtlicher, die zweite dafür länger. Welche du wählst, bleibt natürlich dir überlassen.

Mehr Informationen, sowie Hintergründe findet sich (wie immer) auf php.net. Dort gibt es auch weitere Kalenderfunktionen, die vielleicht nicht gerade häufig gebraucht werden, aber dennoch einen Blick wert sind.


Gerade Zahlen

Es gibt eine ganz einfache Methode, um zu prüfen, ob eine Zahl gerade oder ungerade ist.

Dabei machen wir uns die Tatsache, dass eine gerade Zahl bei einer Division durch 2 immer 0 Rest hat, zunutze.

Den Restwert einer Division erhält man in PHP mit dem Operator % - also so, wie man zum addieren das + verwendet oder für eine Division den /.

Das sieht dann so aus:
$restwert = 4 % 2;
Dabei wird 4 durch 2 dividiert und das Ergebnis ist in diesem Fall 0, da ja 0 Rest bleibt. Würde man die selbe Rechnung mit 5 % 2 ausführen, wäre das Ergebnis 1, weil 5/2 = 2, 1 Rest.

Man erhält also nicht das Ergebnis der Division, sondern lediglich den Restwert - das kann am Anfang etwas verwirrend sein.

Wenn wir jetzt wissen wollen, ob die in der Variable $pruefzahl gespeicherte Zahl gerade ist, benötigen wir einfach nur folgendes:
$restwert = $pruefzahl % 2;
Ist der Restwert 0, handelt es sich um eine gerade Zahl, ist er etwas anderes, handelt es sich um eine ungerade Zahl.

Das kann dann noch beliebig mit if-Abfragen oder ähnlichem kombiniert werden.


Runden

Um einen Wert in PHP ganzzahlig aufzurunden, verwendet man die Funktion ceil:
$aufgerundet = ceil(3.867);
Der Wert der Variable $aufgerundet ist dann 4.

Zum Abrunden gibt es floor, welches ebenso funktioniert.

Gibt man die Werte an, sollte man bedenken, dass Kommazahlen in PHP mit Punkt anstatt mit Komma geschrieben werden. Alternativ kann man natürlich auch eine Variable runden, oder das Ergebnis einer Rechnung, z. B. so:
$abgerundet = floor(13/2);
Die Variable $abgerundet enthält jetzt den Wert 6 (hätten wir aufgerundet, wäre es 7 gewesen).

Möchte man prinzipiell runden oder aber nicht ganzzahlig, dann gibt es noch die Funktion round.

Hierbei kann man zusätzlich angeben, auf wieviele Kommastellen gerundet werden soll:
$runde = round(3.4768, 2);
Die erste Angabe ist dabei der zu rundende Wert (wiederum für das Komma den Punkt verwenden!) und - durch ein Komma getrennt - die Anzahl der Dezimalstellen, auf die gerundet werden soll. In dem Fall wäre das Ergebnis also 3.48


Platzhalter bei MySQL-Abfragen

Während die meisten Suchfunktionen einen Stern als Platzhalter für unbekannte Teile verwenden - also z. B. Daten* für alles, was mit "Daten" beginnt - ist der Platzhalter in MySQL das Prozentzeichen.

Möchte man also z. B. nach allen Einträgen in einem Feld suchen, die den Begriff "tier" enhalten (von Haustier über Tierheim bis Haustierfutter ;-)), dann schaut die Abfrage so aus:
SELECT * FROM tabelle WHERE spaltenname LIKE '%tier%'
Soll das gewünscht Ergebnis "tier" lediglich am Anfang haben (also Tiergarten, Tierfreund etc., aber nicht Faultier oder Arbeitstier), verwendet man das Prozentzeichen lediglich am Ende:
SELECT * FROM tabelle WHERE spaltenname LIKE 'tier%'
Das selbe funktioniert natürlich auch, wenn man es nur am Anfang anwendet. Dann sind die Ergebnisse eben Elterntier, Fabeltier, Stofftier etc., aber eben nicht Tierarzt oder Tierliebe.


gd-lib Basics

Für den Anfang wollen wir einfach nur ein Bild mit einem eingefärbtem Hintergrund erstellen und als Datei abspeichern.

Zunächst sollten wir dazu wissen, ob unser Server überhaupt in der Lage ist, mit der gd-lib zu arbeiten. Am besten, ihr testet das auf eurem (virtuellen) Webserver testet, indem ihr eine PHP-Datei erstellt, die lediglich den PHP-Befehl phpinfo() aufruft, diese auf den Server hochladet und dann aufruft. Dort sollte es dann einen Abschnitt gd geben, falls nicht, bleibt nur den Hoster bitten, GD zu aktivieren, oder lokal auf einem virtuellen Webserver zu arbeiten und es gegebenenfalls dort zu installieren.

Wenn wir etwas mit einem Bild machen wollen, müssen wir auf jeden Fall einen Dateizeiger auf das Bild setzen - salopp ausgedrückt muss unser Bild in einer Variable verfügbar sein. Da wir mit einem neuen Bild arbeiten wollen besteht unser erster Schritt also darin, dieses Bild als "Variable" zu erstellen. Dafür dient die Funktion imagecreate bzw. imagecreatetruecolor. Da php.net die Nutzung von imagecreatetruecolor empfiehlt, werden wir mit dieser Arbeiten.
$bild = imagecreatetruecolor(200, 250);
Die Zahlen in Klammer geben die Breite und die Höhe unseres Bildes an, es wird also in diesem Fall 200 Pixel breit und 250 Pixel hoch werden. Die Hintergrundfarbe ist standardmäßig schwarz.

Damit wir uns das jetzt sofort anschauen können, greife ich gleich ein wenig vor und erkläre, wie man das Bild in eine Datei speichert.

Wir machen aus unserem Bild eine jpg-Grafik und speichern sie als test.jpg ab. (Gif wäre bei einem einfarbigen Bild natürlich logischer, aber das funktioniert mit imagecreatetruecolor nicht.) Diejenigen, die nicht auf einem virtuellen Webserver arbeiten, müssen im Verzeichnis, in dem sie arbeiten, Schreibrechte setzen, sonst funktioniert es nicht.
imagejpeg($bild, "test.jpg");
Wir rufen also die Funktion imagejpeg auf und übergeben als Werte unsere Bildvariable und den Dateinamen, den unser Bild bekommen soll.

Damit wir jetzt auch noch was sehen können, binden wir test.jpg als Bild ein - ganz normal über HTML. Unsere Datei sieht dann also so aus:
<?php
$bild = imagecreatetruecolor(200,250);
imagejpeg($bild, "test.jpg");
?>
<img src="test.jpg" />
Wenn wir sie aufrufen sollte ein 200 x 250 Pixel großer schwarzer Fleck auftauchen.

Da schwarze Flecken aber langweilig sind, färben wir jetzt noch die Grafik ein. Leider ist es in PHP etwas umständlich, eine bestimmte Farbe auszuwählen, sie muss nämlich zunächst mit imagecolorallocate bestimmt werden.
$weiss = imagecolorallocate($bild, 255, 255, 255);
Dabei muss zunächst das Bild angegeben werden und danach die gewünschte Farbe in RGB Werten. In unserem Fall dreimal 255, was als Farbe weiß ergibt. Folgendes würde z. B. ein helles Blau ergeben:
$mittelblau = imagecolorallocate($bild, 203, 215, 230);
Wenn wir jetzt also unsere gewünschte Farbe bestimmt haben, müssen wir nur noch das Bild einfärben. Dazu dient die Funktion imagefill.
imagefill($thumb, 0, 0, $mittelblau);
Als erstes wird das Bild angegeben, das eingefärbt werden soll, danach folgen die x- und y-Koordinaten, bei denen die Füllung beginnen soll. 0, 0 ist also die obere linke Ecke. Offen gestanden kann ich aber keinen Unterschied erkennen, wenn man andere Koordinaten wählt - das Bild wird immer vollständig mit der Farbe gefüllt. Der letzte Wert ist die Farbe, die wir vorher ermittelt haben.

Wenn wir jetzt imagejpeg aufrufen (wie oben) und dann das Bild anzeigen lassen, haben wir das selbe Bild wie vorhin, allerdings mit einer anderen Hintergrundfarbe.

Das gesamte Script sieht jetzt so aus:
<?php
$bild = imagecreatetruecolor(200,250);
$weiss = imagecolorallocate($bild, 255, 255, 255);
$mittelblau = imagecolorallocate($bild, 203, 215, 230);
 
imagefill($bild, 0, 0, $mittelblau);
imagejpeg($bild, "test.jpg");
?>
<img src="test.jpg" />
Mit der gd-lib ist noch viel mehr möglich - ein Beispiel ist hier zu sehen.


gd-lib Text

In Grafiken kann man auch Text einsetzen. Wir gehen dabei von der Grafik aus, die im ersten Beispiel erklärt ist.

Bevor wir die Grafik als Datei speichern, schreiben wir jetzt noch einen Text hinein. Dafür wird die Funktion imagettftext verwendet.
imagettftext($bild, 12, 0, 10, 20, $weiss, "arial.ttf", "Ein einfacher Text");
Hierbei werden im ersten Moment erscheckend viele Argumente übergeben:

Zunächst die Bildvariable, wie auch schon bei allen anderen Arbeiten an Bildern.
Der zweite Wert ist die Font-Größe, in unserem Fall also 12 Pixel.
Der nächste Wert ist der Winkel, in dem der Text geschrieben sein soll. 0 ist dabei ganz normaler Text von links nach rechts. Umso höher der Wert ist, umso mehr wird der Text entgegen dem Uhrzeigersinn gedreht. Bei einem Wert von 90 (Grad) wird der Text von unten nach oben geschrieben.
Die folgenden zwei Werte ergeben die Positionierung des Textes und sind die x- und y-Koordinaten der unteren, linken Ecke des Textes.
Der sechste Wert ist die Farbe, hier in Form einer Variablen angegeben, die mit imagecolorallocate ermittelt wurde.
Danach wird der Pfad zum gewünschten Font angegeben. In dem Beispiel muss die Schriftart also im selben Verzeichnis gespeichert werden und trägt den Namen arial.ttf.
Der letzte Wert ist jetzt der anzuzeigende Text, den man natürlich auch nett über eine Variable übergeben kann. Ist der Text zu lang für das Bild, wird er einfach abgeschnitten.

Die Funktion fügt übrigens nicht nur Text in Grafiken ein, sondern kann auch ein Array zurück liefern, dass die Abmessungen des Textes enthält.

Es gibt auch eine kürzere Methode, um Text einzubinden, wobei man aber die Schriftgröße und den Winkel nicht bestimmen kann. Dabei wird die gewünschte Schriftart zunächst über imageloadfont geladen und kann anschließend verwendet werden - sie muss aber im Bitmapformat vorliegen. Es gibt aber auch 5 vordefinierte Schriftarten, die man verwenden kann, wodurch es auch möglich ist, Texte zu erstellen, wenn man keine Bitmapfonts hat.
imagestring($bild, 3, 10, 10, "Text", $weiss);
Auch hier wird zunächst die Bildvariable angegeben. Danach folgt die gewünschte Schrift. Diese muss entweder zuerst über imageloadfont z. B. in einer Variable gespeichert sein, also:
$schriftart = imageloadfont("fontdatei");
oder man verwendet einen Wert von 1 bis 5, der eine vordefinierte Schriftart auswählt.

Danach werden die x- und y-Koordinaten der linken, oberen Ecke (im Gegensatz zur linken, unteren Ecke bei imagettftext) angegeben, gefolgt vom gewünschten Text und der Farbe.

Wer mit dieser Methode einen Text von unten nach oben laufen lassen möchte, kann die Funktion imagestringup benutzen. Diese ist genauso aufgebaut wie imagestring. Die Koordinaten geben die linke, obere Ecke des ersten Buchstabens an.

Die Varianten mit imagestring bzw. imagestringup haben den Nachteil, dass man entweder einen Bitmapfont braucht, oder aber die begrenzte Auswahl von PHP nutzen muss. Allerdings ist auch die Funktion imagettftext nichts ganz unproblematisch, sie setzt nämlich voraus, dass auf dem Server die Freetype-Bibliothek verfügbar ist.

Eine Lösung für alle Fälle gibt es hier also nicht.


gd-lib Datei

Es ist übrigens auch möglich, eine PHP-Datei als Bild einzubinden. Geht man von den letzten Beispielen aus, wird das Bild nicht in eine Datei geschrieben (einfach nur die Bildvariable in imagejpeg angeben) sondern direkt an den Browser ausgegeben.

Wichtig dabei ist, keinen HTML-Code in der PHP-Datei zu verwenden und vor allem einen Header zu übergeben.

Dieser muss ganz am Anfang einer Datei stehen, lediglich der Aufruf von PHP muss davor erfolgen:
<?php
Header ("Content-Type: image/jpeg");
... &uuml;briger Code ...
?>
Dann kann diese PHP-Datei wie ein Bild eingebunden werden.

Wenn die PHP-Datei also beispielsweise image.php heißt, dann sieht das so aus:
<img src="image.php" />
Übrigens können dabei auch Variablen übergeben werden:
<img src="image.php?text=Ein Test" />



Cookies

Wer benutzerspezifische Daten nicht nur für die Dauer einer Session abspeichern will, wird auf Cookies zurück greifen müssen. Sie sind allerdings etwas unkomfortabler zu benutzen als Sessions.

Gesetzt wird das Cookie über setcookie. Benötigte Angaben sind der Cookiename, sowie ein Wert des Cookies. Ebenfalls ratsam ist eine Gültigkeitsdauer (ansonsten wird es nach dem Schließen des Browsers gelöscht).

Mögliche weitere Angaben - auf die ich hier aber nicht näher eingehen werde - sind Pfadangaben, sowie Server, die zum Lesen berechtigt sind, sowie ein Sicherheitsschalter (also gesetzt oder nicht gesetzt), mit dem festgelegt werden kann, dass das Cookie nur bei einer sicheren Verbindung (z. B. https) gesetzt wird.

Praktisch sieht das dann so aus:
setcookie("phpfuerdich_cookie","Werte",time()+3600);
Damit wird ein Cookie mit dem Namen phpfuerdich_cookie gesetzt, dass als Wert das Wort "Werte" enthält und eine Stunde gültig ist. Wichtig ist, dass vor dem Setzen des Cookies kein anderer Code ausgegeben werden darf, der in der Datei angezeigt wird. Also keine Leerzeile, kein Leerzeichen oder sonst nichts. Möglich sind hingegen reine Code-Zeilen ohne Ausgabe (also z. B. eine Abfrage, um den gewünschten Wert festzulegen).

Die Gültigkeitsdauer ergibt sich aus der aktuellen Uhrzeit (als Timestamp, daher time()) plus der Dauer in Sekunden. In dem Fall 3600 Sekunden, also eine Stunde. Für eine Gültigkeitsdauer von einem Tag wird dann entsprechend time()+3600*24 verwendet.

Der Wert des Cookies ist über eine (fast) ganz normale Variable verfügbar:
$_COOKIE["phpfuerdich_cookie"]
Der Aufbau ist also entsprechend Post- oder Get-Variablen.

Das Problem bei Cookies ist, dass der Wert einfach als ganz normale Zeichenkette gespeichert wird. Mag man also mehrere Werte haben, dann wird es ein wenig umständlicher.

Ich habe dafür eine ziemlich simple Methode verwendet, indem ich die einzelnen Werte mit Trennzeichen versehen habe und daraus dann beim Einlesen mit Hilfe der Funktion explode ein Array gebildet habe.

Das sieht dann z. B. so aus:
$werte = "Name|Strasse|PLZ|Ort";
setcookie("adressliste_cookie",$werte,time()+3600*24*30);
Damit wird ein Cookie mit verschiedenen Werten gesetzt, das 31 Tage gültig ist. Ich verwende als Trennzeichen gerne |, aber es sind natürlich auch viele andere möglich. Komma und Semikolon finde ich nicht so empfehlenswert, da sie schon mal in den Werten selbst vorkommen können.

Das Auslesen funktioniert dann so:
$wertarray = explode("|",$_COOKIE["adressliste_cookie"]);
Name ist dann über $wertarray[0] abrufbar, Strasse über $wertarray[1] usw.

Nicht vergessen, dass Arrays immer mit 0 anfangen!

Wer das Cookie löschen will ruft einfach setcookie nur mit der Namensangabe des Cookies auf:
setcookie("adressliste_cookie");
Auf php.net wird empfohlen, es ohne Wertangaben (also nur "") und mit negativer Geltungsdauer aufzurufen, damit es auch sicher gelöscht wird. Das sieht dann so aus:
setcookie("adressliste_cookie","",time()-3600);
(Es ist natürlich auch jede andere negative Geltungsdauer möglich.)


Explode

Mit explode können Zeichenketten in einzelne Teile zerlegt werden. Dafür gibt es ein Trennzeichen. Die einzelnen Teile werden dann in ein Array gespeichert.
$arrayname = explode("Trennzeichen","Zeichenkette");
Ist die Zeichenkette z. B. in der Variable $liste gespeichert und enthält als Trennzeichen das |, dann sieht das folgendermaßen aus:
$arrayname = explode("|",$liste);
$arrayname ist dann ein ganz normales Array, bei dem über Zahlen auf die einzelnen Werte zugegriffen werden kann (also $arrayname[0], $arrayname[1], $arrayname[2] usw.)

Das Trennzeichen fällt bei dieser Vorgehensweise weg!

Es gibt auch noch eine umgekehrte Funktion - implode - die Zeichenketten aus einem Array erstellt. Sie funktioniert genauso.


Tabelle kopieren mit phpMyAdmin

phpMyAdmin bietet komfortable Möglichkeiten um Tabellen (mit und ohne Daten) zu kopieren.

Dafür wählt man zunächst die gewünschte Tabelle aus (entweder in der linken Menüleiste anklicken oder in der Tabellenübersicht auf Eigenschaften gehen) und geht danach auf Operationen (in der oberen Menüleiste).

Neben der Möglichkeit, die Tabelle umzubenennen, oder sie, so wie sie ist, zu verschieben, kann man dort auch Tabellen kopieren.

Dafür wählt man die Datenbank aus, in die die Tabelle kommen soll und legt dann einen Tabellennamen fest. Anschließend kann man noch wählen, ob man nur die Struktur, Struktur und Daten oder nur Daten (nur sinnvoll, wenn eine Tabelle mit den gleichen Feldern bereits besteht) kopieren möchte.

Achtung: Wenn man die Struktur einer Tabelle kopieren möchte und eine Tabelle gleichen Namens ist bereits vorhanden, muss man zusätzlich einen Haken bei Drop Table setzen, damit sie vor dem Anlegen (der neuen, kopierten Tabelle) gelöscht wird.


CSS mit PHP

Mein Wunsch, eine Stylesheet-Datei dynamisch zu erstellen führte mich logischerweise zu PHP. Und tatsächlich ist es ganz einfach möglich, CSS mit PHP dynamisch zu machen.

Wir verwenden dafür statt der üblichen format.css eine format.php-Datei. In dieser benötigen wir unbedingt eine Header-Anweisung, die ganz an den Anfang der Datei kommt:
<?php
header("Content-type: text/css");
?>
Danach kann man ganz nach Belieben normale CSS-Anweisungen verwenden - oder eben mit PHP Abfragen, switch, if-Anweisungen usw. arbeiten. Wichtig ist jedoch, dass die format.php fehlerfreie CSS-Befehle liefert. Sobald irgendwelcher "unsinniger" Text in der Datei steht, funktioniert keiner der gewünschten Styles.

Überprüfen kann man das ganz einfach, indem man im Browser format.php direkt aufruft - dann bekommt man die durch PHP generierte Format-Datei direkt angezeigt und Fehler fallen sehr schnell auf.




Adventssonntage

Ich wollte herausfinden, wie man das korrekte Datum für den 1. Advent eines beliebigen Jahres berechnen kann und machte mich einfach mal aus Spaß an die Programmierung. Rechnereien mit Datumsangaben finde ich immer schwierig, weil Computer dabei ganz anders denken, als wir Menschen und ich es oft umständlich finde umzudenken und Dinge so ganz anders auszudrücken. Nach einer Weile hatte ich aber eine funktionierende Lösung, die auch gar nicht so furchtbar umständlich war, wie ich befürchtet hatte. Danach machte ich mich im Internet auf die Suche nach fertigen Lösungen, weil ich sie miteinander vergleichen wollte. Relativ schnell stieß ich dabei auf die Funktion strtotime, die tatsächlich wesentlich besser und einfacher ist. Wenn man sie erstmal verstanden hat.

Die Erklärung bei php.net brachte mich nämlich zunächst nicht wirklich weiter. Dort steht: Wandelt ein beliebiges in englischer Textform angegebenes Datum in einen UNIX-Zeitstempel (Timestamp) um.

Okay, Timestamp war mir klar, ich würde also das Ergebnis noch formatieren müssen, aber was versteht man denn bitte unter "ein beliebiges in englischer Textform angegebenes Datum"? Ein sehr schwammiger Begriff.

Die Beispiele zeigten aber sehr schnell, dass strtotime in der Lage ist, unheimlich viele Begriffe zu interpretieren. Man kann z. B. ganz einfach den heutigen Tag in einer Woche angeben lassen, indem man strtotime("+1 week") verwendet. Das gleiche funktioniert natürlich auch mit +1 day oder anderen Angaben. Das ist aber noch nicht alles, man kann sogar sagen, dass man Donnerstag in drei Wochen haben mag, indem man +3 thursday verwendet, oder ähnliche Konstrukte bildet. Zusätzlich kann man auch noch ein beliebiges Datum angeben, von dem aus die Berechnungen stattfinden soll. Man muss es zwar in einen Timestamp umwandeln, aber das ist dank mktime überhaupt kein Problem.

Was das jetzt alles mit dem 1. Advent zu tun hat?

Google hat mir verraten, dass der 1. Advent immer der 1. Sonntag nach dem 26. November ist (das kann man sich natürlich auch selber überlegen ;-)). Ich füttere strtotime also mit diesen Angaben:
<?php
$erster_advent = strtotime("+1 sunday",mktime(0,0,0,11,27,2010));
?>
+1 sunday sorgt dafür, dass der folgende Sonntag berechnet wird. Wenn man nach dem Komma noch einen gültigen Timestamp angibt (oder direkt über mktime berechnen lässt), kann man auch exakt angeben, auf welchen Tag denn der Sonntag folgen soll. In diesem Fall mache ich also mktime-Angaben, die den 27.11.2010 ergeben.

Um das Ergebnis für uns lesbar auszugeben, sollten wir es noch über date formatieren. Das sieht dann so aus:
<?php
echo date("d.m.Y", $erster_advent);
?>
Man kann die beiden Angaben natürlich auch zusammenfassen und das Datum direkt ausgeben und auf die Speicherung in einer Variable verzichten.
<?php
echo date(strtotime("+1 sunday",mktime(0,0,0,11,27,2010)));
?>
In meinem Fall habe ich das Script noch dahingehend erweitert, dass man beim Seitenaufruf festlegen kann, für welches Jahr die Ausgabe erfolgen soll. Die per get übergebene Variable wird aus Sicherheitsgründen noch überpüft. Alles zusammen sieht es dann wie folgt aus:
<?php
if(is_int(intval($_GET["jahr"])))
{
  $jahr = intval($_GET["jahr"]);
}
else
{
  $jahr = date("Y");
}
echo "Adventssonntage im Jahr ",$jahr,": <br />";
echo "1. Advent: ",date("d.m.Y",strtotime("+1 sunday",mktime(0,0,0,11,27,$jahr))),"<br />";
echo "2. Advent: ",date("d.m.Y",strtotime("+2 sunday",mktime(0,0,0,11,27,$jahr))),"<br />";
echo "3. Advent: ",date("d.m.Y",strtotime("+3 sunday",mktime(0,0,0,11,27,$jahr))),"<br />";
echo "4. Advent: ",date("d.m.Y",strtotime("+4 sunday",mktime(0,0,0,11,27,$jahr))),"<br />";
?>
Wenn man immer nur das aktuelle Jahr verwenden möchte, kann man natürlich die Abfrage der get-Variable weglassen und entweder nur $jahr = date("Y"); nehmen, oder direkt in der mktime-Anweisung date("Y") angeben, das würde dann so aussehen:
<?php
echo "1. Advent: ",date("d.m.Y",strtotime("+1 sunday",mktime(0,0,0,11,27,date("Y"))),"<br />";
?>
Ausgegeben bekommen wir dann:

Adventssonntage im Jahr 2024:
1. Advent: 01.12.2024
2. Advent: 08.12.2024
3. Advent: 15.12.2024
4. Advent: 22.12.2024

Auf die gleiche Weise ist es natürlich auch möglich all die (Feier)tage zu berechnen, die sich auf Ostern beziehen (also Rosenmontag, Aschermittwoch, Himmelfahrt, Pfingsten, etc.). In dem Fall muss man dann als zweite Angabe für strtotime das Osterdatum verwenden. Und so kann ich euch jetzt z. B. verraten, dass der nächste Rosenmontag am 02.03.2025 ist (jeweils 48 Tage vor dem Ostersonntag).


Kerze mit gd-lib 1

Winterzeit, Kerzenzeit. Warum nicht einmal eine brennende Kerze mit PHP erstellen? Dank gd-lib ist das gar keine große Sache.

Zunächst brauchen wir eine png-Grafik mit einer Kerzenflamme. Wir verwenden png, weil es transparente Flächen ermöglicht und wir somit später eine beliebige Hintergrundfarbe wählen können. Wenn dir das nicht wichtig ist, kannst du natürlich auch mit einer jpg-Datei arbeiten, brauchst dann aber später andere Befehle. Erstelle dir jetzt entweder eine eigene Flamme, oder verwende einfach meine, indem du sie dir hinunter lädst:

Kerzenflamme

Als nächstes brauchen wir eine PHP-Datei. Wir werden die Datei am Ende so schreiben, dass die Datei selbst unser Bild ergibt. Da das allerdings den Nachteil hat, dass wir keine Fehlermeldungen angezeigt bekommen, lassen wir das Bild zunächst in eine Datei schreiben und anzeigen und ändern das erst am Ende.

Wir beginnen also zunächst damit, die Breite und Höhe des späteren Bildes in eine Variable zu schreiben und dann daraus ein leeres Bild zu erzeugen und in eine Datei zu schreiben. Dieses Bild lassen wir uns dann auch gleich anzeigen.
<?php
$breite = 150;
$hoehe = 300;
$kerze = imagecreatetruecolor($breite, $hoehe);
imagepng($kerze, "kerze.png");
?>
<img src="kerze.png" alt="Kerze" />
Mit imagecreatetruecolor($breite, $hoehe) erstellen wir ein Bild mit der von uns festgelegten Breite von 150 und einer Höhe von 300 Pixeln. Wir speichern die Informationen zu dem Bild in der Variable kerze und können damit später jederzeit das Bild ansprechen. Um das Bild als png zu speichern verwenden wir am Ende den Befehl imagepng($kerze, "kerze.png"). Der erste Wert in der Klammer ist die Variable in der unser Bild gespeichert wurde, der zweite Wert ist der Dateiname. Er muss in Anführungszeichen gesetzt werden (oder als Variable übergeben werden). Es kann passieren, dass du die Zugriffsberechtigungen für das Verzeichnis, in dem die Datei später liegen soll, ändern musst. Am Schluss geben wir einfach im HTML-Code an, dass das Bild angezeigt werden soll. Bisher sieht es alledings nur so aus:

Kerze

Eine große schwarze Fläche ist natürlich nicht das, was wir uns vorstellen, also färben wir zunächst den Hintergrund ein. Ich verwende in diesem Beispiel als Hintergrundfarbe ein helles Grau, du kannst aber natürlich auch andere Farben wählen. Wir ergänzen den Code zwischen imagecreatetruecolor und imagepng, so dass er dann so aussieht:
<?php
$breite = 150;
$hoehe = 300;
$kerze = imagecreatetruecolor($breite, $hoehe);
<b>$hintergrundfarbe = imagecolorallocate($kerze, 200, 200, 200);
imagefill($kerze, 0, 0, $hintergrundfarbe);</b>
imagepng($kerze, "kerze.png");
?>
<img src="kerze.png" alt="Kerze" />
Was passiert hier?

Zuerst legen wir eine Farbe für den Hintergrund fest. Wir nennen die Variable hintergrundfarbe und verwenden die Anweisung imagecolorallocate($kerze, 200, 200, 200), um die Farbe darin zu speichern. imagecolorallocate braucht dafür zunächst das Bild, in dem die Farbe angewendet werden soll - in unserem Fall also das in der Variable kerze gespeicherte - und danach die Farbangaben. Diese Farbangaben sind in RGB, also Rot-, Blau- und Grünwerte. Nimmt man bei allen drei Werten 255, so erhält man weiß. Alle Werte auf 0 wäre schwarz. Im Normalfall kann dir ein Grafikprogramm diese Werte anzeigen.

Nachdem die Farbe jetzt verfügbar ist, können wir das Bild damit füllen. Dafür gibt es die Funktion imagefill. Auch hier müssen wir zuerst das Bild angeben, das gefüllt werden soll. Danach geben wir die Koordinaten an, ab denen die Füllfarbe aufgetragen werden soll. Die erste Angabe ist die x-Koordinate, die zweite die y-Koordinate. Unsere Angabe 0, 0 ergibt also links oben. Als letzten Wert übergeben wir die gewünschte Farbe, die bei uns in der Variable hintergrundfarbe gespeichert ist.

Jetzt haben wir zwar immer noch nur eine leere Fläche, aber zumindest ist die Hintergrundfarbe schon die von uns gewünschte:

Kerze

Der nächste Schritt besteht darin, dass wir festlegen, wie breit unsere Kerze sein soll und diesen Wert in einer Variable abspeichern. Außerdem legen wir mit imagecolorallocate eine Farbe für unsere Kerze fest. Ich nehme dafür einen lila Farbton. Die Angaben müssen vor imagepng($kerze, "kerze.png") erfolgen.
$kerzendicke = 100;
$kerzenfarbe = imagecolorallocate($kerze, 160, 119, 191);
Als nächstes wollen wir die Kerze in das Bild einfügen. Dafür werden wir einfach ein Rechteck in der gewünschten Farbe ins Bild setzen. Die Funktion dafür nennt sich imagefilledrectangle und benötigt von uns genaue Koordinatenangaben, wo das Rechteck gezeichnet werden soll. Aus diesem Grund berechnen wir zunächst diese Koordinaten.
$kerze_x1 = ($breite - $kerzendicke) / 2;
$kerze_y1 = 80;
$kerze_x2 = $kerze_x1 + $kerzendicke;
$kerze_y2 = $hoehe - $kerze_x1;
Das sieht jetzt erstmal unheimlich kompliziert aus, ist es aber eigentlich gar nicht. Wir gehen es einfach Schritt für Schritt gemeinsam durch:

Die ersten zwei Variablen kerze_x1 und kerze_y2 werden später angeben, wo die obere, linke Ecke unserer Kerze ist. Die zweiten zwei Variablen ergeben dann die untere, rechte Ecke.

kerze_x1: Da die Kerze nicht links ins Eck gequetscht sein soll, verwenden wir einen Rand rund um die Kerze herum. Die Breite dieses Randes ergibt sich aus der gesamten Bildbreite - in der Variable breite gespeichert - abzüglich der Kerzendicke, die in der Variable kerzendicke gespeichert ist. Da wir links und rechts gleich viel Randfläche haben wollen, dividieren wir diesen Wert noch durch zwei.
kerze_y1: Die Kerze soll nicht am obersten Bildrand beginnen, sondern ein Stück weiter unten. Ich nehme bis auf weiteres hier einfach 80 Pixel als Wert, da ich weiß, dass die Kerzenflamme 60 Pixel hoch ist und ich somit noch etwas Puffer haben werde.
kerze_x2: Diesen Wert berechnen wir einfach aus der ersten x-Koordinate und der gewünschten Kerzendicke, indem wir die beiden Werte addieren.
kerze_y2: Für diesen Wert, der angibt, wie weit die Kerze nach unten geht, könnten wir einfach die Bildhöhe verwenden. Da wir aber schon links und rechts der Kerze einen schönen Rand haben, wollen wir den gleichen Rand auch für unten verwenden und ziehen daher von der festgelegten Bildhöhe die Variable kerze_x1 ab, da dieser Wert der Randbreite entspricht.

Nachdem wir all diese Koordinaten berechnet haben, können wir als nächstes unser Rechteck zeichnen:
imagefilledrectangle($kerze, $kerze_x1, $kerze_y1, $kerze_x2, $kerze_y2, $kerzenfarbe);
Ich vermute, dir ist jetzt schon klar, was die ganzen Angaben bei imagefilledrectangle bewirken, oder?

Der erste Wert ist unser Bild. Danach folgen die vier Angaben für die Koordinaten, wobei die ersten zwei Werte die x- und y-Koordinaten für den Startpunkt und die nächsten zwei Werte die Angaben für den Endpunkt sind. Als letztes geben wir unsere vorher festgelegte Farbe an und das ganze sieht dann so aus:

Kerze

So ganz nach Kerze sieht es immer noch nicht aus, daher kümmern wir uns als nächstes um einen Docht.

Auch der Docht besteht aus einem einfachen Rechteck, das wir schwarz färben. Wir müssen also zunächst die Farbe schwarz festlegen.
$schwarz = imagecolorallocate($kerze, 0, 0, 0);
Danach brauchen wir wieder ein wenig Rechnerei, um die richtigen Koordinaten für unseren Docht herauszufinden:
$docht_x1 = $kerze_x1 + ($kerzendicke / 2) - 1;
$docht_y1 = $kerze_y1 - 13;
imagefilledrectangle($kerze, $docht_x1, $docht_y1, $docht_x1+2, $docht_y1+10, $schwarz);
Dieses Mal legen wir nur die Variablen für die Anfangskoordinaten fest und ich zeige euch, dass man auch direkt beim Aufruf der Funktion imagefilledrectangle Berechnungen durchführen kann.

Den x1-Wert für den Docht berechnen wir anhand des horizontalen Beginns der Kerze - also der Position kerze_x1, sowie der Hälfte der Kerzendicke, damit er auch in der Mitte der Kerze steht. Zusätzlich ziehen wir ein weiteres Pixel ab, weil unser Docht insgesamt 2 Pixel breit sein soll. Damit er exakt zentriert ist, muss er also ein Pixel weiter links als die eigentliche Mitte ist, anfangen.

Der y1-Wert ergibt sich aus der vertikalen Startposition der Kerze, abzüglich 13 Pixel. Diese 13 Pixel setzen sich aus 10 Pixel, die wir als Dochthöhe verwenden werden und einem Abstand von 3 Pixeln zwischen Docht und Kerze zusammen. Man kann Docht und Kerze natürlich auch aneinander stoßen lassen, dann verwendet man eben nur die gewünschte Dochthöhe als Abzug.

Als nächstes ziehen wir mit imagefilledrectangle unser Rechteck auf. Die ersten drei Angaben kennst du schon: Das Bild und die Startpunkte des Dochtes. Da wir die Endpunkte dieses Mal nicht in Variablen gespeichert habe, schreiben wir diese kleinen Berechnungen direkt als Werte in die Funktion. Für den 2. x-Wert verwenden wir docht_x1+2, also den Beginn des Dochtes plus 2 Pixel, die er breit sein soll. Genauso funktioniert auch die Berechnung des 2. y-Wertes, nur das wir hier von docht_y1 ausgehen und 10 Pixel hinzuaddieren, die der Docht ja hoch sein sollte.

Jetzt sollte es so aussehen - ist doch schon fast eine Kerze, oder?

Kerze

Natürlich soll unsere Kerze auch noch brennen und nicht nur ausgeblasen sein und so kommt jetzt unsere Flamme ins Spiel. Speichere sie an der gleichen Stelle, wie auch deine PHP-Datei (oder passe den Pfad entsprechend an). Wir kopieren jetzt diese Flamme in unser Bild. Dazu müssen wir zuerst die Flamme in einer Variable abspeichern:
$flamme = imagecreatefrompng("flamme.png");
Über imagecreatefrompng("Dateiname") rufen wir unsere Flammengrafik auf. Wenn deine Flamme nicht als png-Datei vorliegt, musst du eine andere Funktion aufrufen - z. B. imagecreatefromjpeg für jpg-Dateien. In der Klammer gibst du den Dateinamen in Anführungszeichen an.

Um die Flamme jetzt ins Bild zu bekommen, müssen wir auch an dieser Stelle wieder die notwendigen Koordinaten berechnen.
$flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - 13;
$flamme_y1 = $kerze_y1 - 62;
imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, 26, 60);
flamme_x1 ergibt sich - ähnlich wie der Docht - aus dem horizontalen Startpunkt der Kerze plus der Hälfte der Kerzendicke. Dieses Mal ziehen wir davon aber nicht nur ein Pixel ab, sondern 13. Auf die 13 kommen wir durch die Breite der Flammengrafik. Diese beträgt 26 Pixel. Die Hälfte davon ist dann unsere 13.

Auch flamme_y1 wird ähnlich wie der Docht berechnet. Die 62 entsteht durch eine Höhe des Ausgangsbildes von 60 Pixel, und weiteren 2 Pixel, die ich als Abstand zur Kerze haben möchte.

Um das anschaulicher darzustellen, zeige ich in diesem Beispiel, wie es aussehen würde, wenn die Breite und die Höhe der Flamme in einer Variable gespeichert wäre:
$flammenbreite = 26;
$flammenhoehe = 60;
$flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - ($flammenbreite / 2);
$flamme_y1 = $kerze_y1 - $flammenhoehe - 2;
Ich bevorzuge im Normalfall die zweite Variante, da sie flexibler ist. Welche du nimmst, bleibt aber selbstverständlich dir überlassen.

Was wir jetzt noch immer nicht haben, ist die Flamme im Bild. Dafür gibt es die Funktion imagecopy.
imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite, $flammenhoehe);
Hier geben wir zunächst wie gewohnt die Variable kerze an, in der unser gesamtes Bild gespeichert ist. Die zweite Angabe ist die Variable, in der wir die Grafik gespeichert haben, die in unser Bild hinein kopiert werden soll. Bei uns ist das also die Variable flamme. Die nächsten zwei Angaben sind die x- und y-Koordinaten, an die das Bild kopiert werden soll. Die zwei darauf folgenden Werte geben an, wo im zu kopierenden Bild, der Kopiervorgang starten soll. Da wir das gesamte Flammenbild kopieren wollen, geben wir also einfach 0, 0 an, um links oben zu beginnen. Die letzten zwei Werte geben an, wieviel kopierte werden soll. Zuerst die Breite und dann die Höhe. Da wir immer noch das gesamte Bild haben wollen, geben wir hier unsere zwei Variablen flammenbreite und flammenhoehe wieder an. Wenn wir die Werte nicht in Variablen gespeichert haben, können wir natürlich auch direkt die Zahlen hinschreiben.

Und schon haben wir eine richtige, brennende Kerze:

Kerze

Was wir jetzt noch ändern wollen ist die Speicherung des Bildes. Bisher speichern wir am Ende unser Bild als png-Datei auf dem Server. Eigentlich wollen wir aber einfach die PHP-Datei als Grafik aufrufen können. Dazu benötigen wir eine Header-Angabe in der Datei. Diese muss ganz am Anfang erfolgen und es darf keinerlei Text etc. ausgegeben werden - ein jeder echo-Befehl oder jede Fehlermeldung, würde also unser Bild dazu bringen, nicht zu funktionieren.

Für eine png-Datei verwenden wir die Header-Angabe Header("Content-Type: image/png").
Header("Content-Type: image/png");
Auch am Ende unserer Datei müssen wir noch etwas verändern. Zunächst muss der HTML-Code zur Anzeige des Bildes entfernt werden, da dieser eine Ausgabe darstellen würde. Außerdem müssen wir PHP anweisen, das Bild nicht länger in einer Datei zu speichern, sondern es nur in ein png umzuwandeln. Dafür ändern wir die Angaben bei imagepng.
imagepng($kerze);
Wir geben also einfach keinen Dateinamen mehr an und lassen den kompletten zweiten Wert weg. Jetzt kann das Bild in jeder beliebigen Datei über den normalen HTML-Code img aufgerufen werden. Als Datei gibt man dann die PHP-Datei an, also z. B.
<img src="kerze.php" />
Der gesamte Code sieht jetzt so aus (mit Zeilennummern dieses Mal - diese gehören nicht zum eigentlichen Code):
  1. <?php
  2. Header("Content-Type: image/png");
  3. $breite = 150;
  4. $hoehe = 300;
  5. $kerze = imagecreatetruecolor($breite, $hoehe);
  6. $hintergrundfarbe = imagecolorallocate($kerze, 200, 200, 200);
  7. imagefill($kerze, 0, 0, $hintergrundfarbe);
  8. $kerzendicke = 100;
  9. $kerzenfarbe = imagecolorallocate($kerze, 160, 119, 191);
  10. $kerze_x1 = ($breite - $kerzendicke) / 2;
  11. $kerze_y1 = 80;
  12. $kerze_x2 = $kerze_x1 + $kerzendicke;
  13. $kerze_y2 = $hoehe - $kerze_x1;
  14. imagefilledrectangle($kerze, $kerze_x1, $kerze_y1, $kerze_x2, $kerze_y2, $kerzenfarbe);
  15. $schwarz = imagecolorallocate($kerze, 0, 0, 0);
  16. $docht_x1 = $kerze_x1 + ($kerzendicke / 2) - 1;
  17. $docht_y1 = $kerze_y1 - 13;
  18. imagefilledrectangle($kerze, $docht_x1, $docht_y1, $docht_x1+2, $docht_y1+10, $schwarz);
  19. $flamme = imagecreatefrompng("media/flamme.png");
  20. $flammenbreite = 26;
  21. $flammenhoehe = 60;
  22. $flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - ($flammenbreite / 2);
  23. $flamme_y1 = $kerze_y1 - $flammenhoehe - 2;
  24. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite, $flammenhoehe);
  25. imagepng($kerze);
  26. ?>
Und im zweiten Teil verrate ich euch, wie man die Kerze dazu bringt, hinunter zu brennen.


Kerze mit gd-lib 2

Dieses Mal wollen wir, dass die Kerze nicht einfach nur herumsteht und brennt, sondern dass sie zusätzlich herab brennt. Wir beginnen dafür mit dem ursprünglichen Code, der Kerze, ändern ihn aber zunächst an zwei Stellen ab. Zuerst schreiben wir eine Raute (#) vor die Headerangabe, damit diese von PHP als Kommentar betrachtet und nicht ausgeführt wird. Dann ändern wir noch ganz am Ende die Funktion imagepng, so dass unser Bild wieder in eine Datei geschrieben wird. Das Bild lassen wir dann natürlich auch wieder anzeigen.

Für die bessere Übersichtlichkeit habe ich dieses Mal im Code die Zeilennummern mit angeben. Diese gehören nicht zum eigentlichen Code!
  1. <?php
  2. #Header("Content-Type: image/png");
  3. $breite = 150;
  4. $hoehe = 300;
  5. $kerze = imagecreatetruecolor($breite, $hoehe);
  6. $hintergrundfarbe = imagecolorallocate($kerze, 200, 200, 200);
  7. imagefill($kerze, 0, 0, $hintergrundfarbe);
  8. $kerzendicke = 100;
  9. $kerzenfarbe = imagecolorallocate($kerze, 160, 119, 191);
  10. $kerze_x1 = ($breite - $kerzendicke) / 2;
  11. $kerze_y1 = 80;
  12. $kerze_x2 = $kerze_x1 + $kerzendicke;
  13. $kerze_y2 = $hoehe - $kerze_x1;
  14. imagefilledrectangle($kerze, $kerze_x1, $kerze_y1, $kerze_x2, $kerze_y2,$kerzenfarbe);
  15. $schwarz = imagecolorallocate($kerze, 0, 0, 0);
  16. $docht_x1 = $kerze_x1 + ($kerzendicke / 2) - 1;
  17. $docht_y1 = $kerze_y1 - 13;
  18. imagefilledrectangle($kerze, $docht_x1, $docht_y1, $docht_x1+2, $docht_y1+10,$schwarz);
  19. $flamme = imagecreatefrompng("flamme.png");
  20. $flammenbreite = 26;
  21. $flammenhoehe = 60;
  22. $flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - ($flammenbreite / 2);
  23. $flamme_y1 = $kerze_y1 - $flammenhoehe - 2;
  24. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite,$flammenhoehe);
  25. imagepng($kerze, "kerze.png");
  26. ?>
  27. <img src="kerze.png" alt="Kerze" />
Angezeigt wird dann wieder die schon aus dem ersten Teil bekannte Kerze:

Kerze

Wenn die Kerze ein Stück herunter gebrannt ist, ist sie natürlich nicht mehr so hoch wie vorher. Für uns heißt das, wir lassen sie einfach ein Stück weiter unten beginnen. Da wir in unserem Code die meisten Werte bereits in Variablen speichern fällt uns das sehr leicht. Wir müssen eine einzige Variable verändern, nämlich die Variable kerze_y1. Damit legen wir nicht nur die Startposition der Kerze fest, sondern haben zusätzlich auch noch die Position des Dochtes und der Flamme bestimmt und daher auch verändert.

Wenn ich den Wert jetzt also z. B. auf 120 erhöhe, würde die Kerze so aussehen:

Kerze

Das funktioniert zwar sehr einfach, ist aber für unser Vorhaben zu statisch, wir wollen schließlich eine immer weiter herab schmelzende Kerze und nicht einfach nur eine kleinere Kerze. Wir müssen also dazu übergehen, den Startpunkt nicht fix in unsere PHP-Datei zu schreiben sondern ebenfalls zu berechnen.

Im ersten Schritt verändern wir dafür die Positionen der einzelnen Anweisungen etwas. Wir setzen die zwei Variablen zur Flammengröße flammenbreite und flammenhoehe vor die ersten Berechnungen, also spätestens in die Zeile 9 und 10. Ich persönlich finde es übersichtlicher, wenn solche Angaben direkt am Anfang der Datei stehen und werde sie daher direkt nach den Variablen, die unsere Bildhöhe und -breite definieren in die Zeilen 5 und 6 setzen:
  1. <?php
  2. #Header("Content-Type: image/png");
  3. $breite = 150;
  4. $hoehe = 300;
  5. $flammenbreite = 26;
  6. $flammenhoehe = 60;
  7. $kerze = imagecreatetruecolor($breite, $hoehe);
  8. $hintergrundfarbe = imagecolorallocate($kerze, 200, 200, 200);
  9. imagefill($kerze, 0, 0, $hintergrundfarbe);
  10. $kerzendicke = 100;
  11. $kerzenfarbe = imagecolorallocate($kerze, 160, 119, 191);
  12. $kerze_x1 = ($breite - $kerzendicke) / 2;
  13. $kerze_y1 = 80;
  14. $kerze_x2 = $kerze_x1 + $kerzendicke;
  15. $kerze_y2 = $hoehe - $kerze_x1;
  16. imagefilledrectangle($kerze, $kerze_x1, $kerze_y1, $kerze_x2, $kerze_y2, $kerzenfarbe);
  17. $schwarz = imagecolorallocate($kerze, 0, 0, 0);
  18. $docht_x1 = $kerze_x1 + ($kerzendicke / 2) - 1;
  19. $docht_y1 = $kerze_y1 - 13;
  20. imagefilledrectangle($kerze, $docht_x1, $docht_y1, $docht_x1+2, $docht_y1+10, $schwarz);
  21. $flamme = imagecreatefrompng("flamme.png");
  22. $flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - ($flammenbreite / 2);
  23. $flamme_y1 = $kerze_y1 - $flammenhoehe - 2;
  24. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite, $flammenhoehe);
  25. imagepng($kerze, "kerze.png");
  26. ?>
  27. <img src="kerze.png" alt="Kerze" />
Jetzt können wir im nächsten Schritt beginnen, die Variable kerze_y1 zu berechnen. Wir verwenden dafür die Flammenhöhe (Variable flammenhoehe) und als oberen Abstand den Rand, der schon an allen anderen Seiten unserer Kerze existiert und dem Wert in der Variable kerze_x1 entspricht.
  1. $kerze_y1 = $flammenhoehe + $kerze_x1;
Wenn wir jetzt die Kerze etwas weiter nach unten gebrannt haben wollen, müssen wir nur noch die Pixel, die bereits weg sein sollen, hinzu addieren. Wollen wir also z. B. dass unsere Kerze bereits 50 Pixel nach unten gebrannt ist, verwenden wir:
  1. $kerze_y1 = $flammenhoehe + $kerze_x1 + 50;
Oder wir machen es gleich ganz ordentlich und schreiben auch diesen Wert in eine Variable:
  1. $abgebrannt = 50;
  2. $kerze_y1 = $flammenhoehe + $kerze_x1 + $abgebrannt;
Das sieht dann so aus:

Kerze

Jetzt sieht die Kerze zwar immer noch bei jedem Aufruf gleich aus, aber die wichtigsten Vorarbeiten sind endlich erledigt. Als nächstes können wir uns mal wieder ans Rechnen machen.

Wir werden ein Datum festlegen, ab dem unsere Kerze brennt, ausrechnen, wie lange dieses Startdatum bereits zurück liegt und den Wert in der Variable abgebrannt dementsprechend erhöhen. Für unser Beispiel gehe ich davon aus, dass unsere Kerze am 12.3.2024 angezündet wurde.
  1. $startdatum = mktime(0,0,0,3,12,2024);
  2. $brenndauer = time() - $startdatum;
  3. $brenndauer = $brenndauer / (60 * 60);
  4. $brenndauer = round($brenndauer,0);
  5. $abgebrannt = $brenndauer;
Zuerst legen wir also ein Startdatum fest. Dafür benötigen wir die Funktion mktime. Diese sorgt dafür, dass PHP das Datum in einen Timestamp umrechnet. Die Angaben bei mktime sind Stunden, Minuten, Sekunden, Monat, Tag, Jahr. Bitte gib alle Zeilen ohne führende Null ein (also nicht 04, sondern 4) und beachte, dass zuerst der Monat und dann erst der Tag angegeben wird.

Der zweite Schritt besteht darin, zu berechnen, wie viel Zeit seit diesem Startzeitpunkt bereits vergangen ist. Dafür ziehen wir einfach das Startdatum vom aktuellen Timestamp ab. Da wir diesen ganz einfach über time() bekommen können, benötigen wir keine extra Variable dafür. Damit hätten wir Anzahl der Sekunden.

Wir wollen aber lieber nur Stunden als Wert haben und dividieren das daher noch durch "60 (Sekunden) * 60 (Minuten)", weil jede Stunde 3600 (60 * 60) Sekunden hat.

Da wir auch noch einen ganzzahligen Wert haben wollen, runden wir das bisherige Ergebnis noch mit der Funktion round, der wir als ersten Wert die Zahl, die gerundet werden soll - also unsere Variable brenndauer - und als zweiten Wert die Anzahl der gewünschten Nachhkommastellen - bei uns keine und daher 0 - übergeben.

Im letzten Schritt weisen wir der Variable abgebrannt noch den Wert der Brenndauer zu.

Ich bevorzuge an dieser Stelle eine zusammengesetzte Schreibweise, daher sieht der Code bei mir dann so aus:
  1. $startdatum = mktime(0,0,0,3,12,2024);
  2. $brenndauer = round((time() - $startdatum) / (60 * 60));
  3. $abgebrannt = $brenndauer;
Und unsere Kerze sieht jetzt so aus:

Kerze

Ups, da ist wohl was schief gelaufen. Unsere Kerze sieht ja gar nicht mehr wie eine richtige Kerze aus. Eher wie ein kleines Häufchen Elend. Was ist passiert?

Da wir als Wert für abgebrannt einfach die Brenndauer in Stunden angegeben haben, kommen wir bei einem Brennbeginn am 12.3.2024 auf eine Brenndauer von 400 Stunden. Bei einer Bildhöhe von 300 Pixel beginnt die Kerze also erst bei -100 Pixel. Das ist viel zu tief.

Eine erste Maßnahme besteht darin, die Kerze weniger stark brennen zu lassen. Statt dem einen Pixel, das sie zur Zeit pro Stunde herunter brennt, könnten wir sie nur halb so stark brennen lassen, indem wir einfach unsere Berechnung ein wenig verändern:
  1. $brenndauer = round((time() - $startdatum) / (60 * 60));
  2. $abgebrannt = $brenndauer / 2;
Damit brennt die Kerze zwar langsamer, aber irgendwann wird sie dennoch herunter gebrannt sein. Wir müssen also die Höhe, die abgebrannt ist begrenzen und z. B. sagen, dass die Kerze um maximal 180 Pixel abgebrannt sein darf:
  1. $brenndauer = round((time() - $startdatum) / (60 * 60));
  2. $abgebrannt = $brenndauer / 2;
  3. if($abgebrannt > 180)
  4. $abgebrannt = 180;
Wir überprüfen also mit einer if-Anweisung, ob die Variable abgebrannt über 180 Pixel liegt und setzen sie, sofern dies der Fall ist, bei 180 fest. Und so sieht das dann aus:

Kerze

Schöner wäre es jetzt natürlich, den Wert, den die Kerze maximal hinunter brennen darf, nicht fix zu setzen, sondern wiederum zu berechnen. Das könnte dann so aussehen:
  1. $brenndauer = round((time() - $startdatum) / (60 * 60));
  2. $abgebrannt = $brenndauer / 2;
  3. $max_abgebrannt = $hoehe - (2 * $kerze_x1 ) - $flammenhoehe - 20;
  4. if($abgebrannt > $max_abgebrannt)
  5. $abgebrannt = $max_abgebrannt;
Hier legen wir zusätzlich eine Variable max_abgebrannt fest und berechnen sie aus der Gesamhöhe des Bild, abzüglich zweimal Rand (Variable kerze_x1) für oben und unten, abzüglich der Flammenhöhe, abzüglich 20 Pixel, die wir als Mindesthöhe für die Kerze haben wollen. Die Kerze wird dann nie kleiner als 20 Pixel sein:

Kerze

Einen Fehler hat die Kerze in meinen Augen jetzt aber immer noch: Wenn sie am untersten Rand ist, geht so eine Kerze üblicherweise aus und brennt nicht noch munter weiter, wie unsere das im Moment noch macht. Wir wollen also die Kerze löschen, wenn sie zu klein geworden ist. Dafür verwenden wir eine weitere if-Anweisung, die dafür sorgt, dass die Flamme nur dann ins Bild kopiert wird, wenn die Kerze tatsächlich noch groß genug ist, um zu brennen.
  1. if($abgebrannt < $max_abgebrannt)
  2. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite, $flammenhoehe);
Hier wird einfach überprüft, ob die Variable abgebrannt kleiner als die maximale Höhe ist und nur dann wird die Flamme ins Bild kopiert. Ansonsten sehen wir einfach nur den Docht.

Kerze

Am Ende musst du die Raute vor der Header-Angabe wieder entfernen und auch die letzte Zeile wieder auf den ursprünglichen Wert ändern, damit du die Datei wieder direkt als Bild einbinden kannst.

Natürlich sind den Möglichkeiten hier bei weitem noch keine Grenzen gesetzt. Wir könnten statt der Flamme auch noch Rauch auf die Kerze setzen, wenn sie ausgegangen ist, oder in das Bild schreiben, seit wann die Kerze schon brennt. Ebenso ist es möglich, die Datei dahingehend zu verändern, dass man Parameter mit übergeben kann und die Kerze somit direkt beim Einbinden dynamisch gestalten kann. Du kannst sie auch stärker oder schwächer brennen lassen. Diese Kerze kann aber genauso die Grundlage für einen ganze Adventskranz voller Kerzen sein.

Kerze Kerze Kerze Kerze Kerze

Was auch immer du daraus machst, hier ist noch einmal der vollständige Code:
  1. <?php
  2. Header("Content-Type: image/png");
  3. $breite = 150;
  4. $hoehe = 300;
  5. $flammenbreite = 26;
  6. $flammenhoehe = 60;
  7. $kerze = imagecreatetruecolor($breite, $hoehe);
  8. $hintergrundfarbe = imagecolorallocate($kerze, 200, 200, 200);
  9. imagefill($kerze, 0, 0, $hintergrundfarbe);
  10. $kerzendicke = 100;
  11. $kerzenfarbe = imagecolorallocate($kerze, 160, 119, 191);
  12. $kerze_x1 = ($breite - $kerzendicke) / 2;
  13. $startdatum = mktime(0,0,0,3,12,2024);
  14. $brenndauer = round((time() - $startdatum) / (60 * 60));
  15. $abgebrannt = $brenndauer / 2;
  16. $max_abgebrannt = $hoehe - (2 * $kerze_x1 ) - $flammenhoehe - 20;
  17. if($abgebrannt > $max_abgebrannt)
  18. $abgebrannt = $max_abgebrannt;
  19. $kerze_y1 = $flammenhoehe + $kerze_x1 + $abgebrannt;
  20. $kerze_x2 = $kerze_x1 + $kerzendicke;
  21. $kerze_y2 = $hoehe - $kerze_x1;
  22. imagefilledrectangle($kerze, $kerze_x1, $kerze_y1, $kerze_x2, $kerze_y2, $kerzenfarbe);
  23. $schwarz = imagecolorallocate($kerze, 0, 0, 0);
  24. $docht_x1 = $kerze_x1 + ($kerzendicke / 2) - 1;
  25. $docht_y1 = $kerze_y1 - 13;
  26. imagefilledrectangle($kerze, $docht_x1, $docht_y1, $docht_x1+2, $docht_y1+10, $schwarz);
  27. $flamme = imagecreatefrompng("flamme.png");
  28. $flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - ($flammenbreite / 2);
  29. $flamme_y1 = $kerze_y1 - $flammenhoehe - 2;
  30. if($abgebrannt < $max_abgebrannt)
  31. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite, $flammenhoehe);
  32. imagepng($kerze);
  33. ?>



Das komplette Tutorial findet sich unter http://www.schattenbaum.net/php