InhaltsverzeichnisAnleitung für EntwicklerReferenzhandbuch

# Anleitung für Entwickler

## Kochbuch

### Datenbanken

#### Allgemeines zum Verständnis

##### Welche Features werden unterstützt?

Das Yana-Framework bietet eine API zum Arbeiten mit Datenbanken, welche auf PEAR-DB basiert. Diese API erweitert die Fähigkeiten von PEAR um folgende Features:

- Unterstützung von Datenbankschemata
- ... durch die Unterstützung von Schemata sind folgende zusätzlich Features möglich, die PEAR-DB nicht anbietet:
  - automatische Validierung von Queries gegen das Datenbankschema
  - automatisiertes Auflösen von Fremdschlüsselbeziehungen
  - automatische Typ-Prüfung vor Input/Update, mit den zusätzlichen Datentypen "select", "url", "ip" und "mail"
  - automatisches Logging von Datenbankereignissen
  - automatisches Erstellen von Backups gelöschter Datensätze in Log-Dateien
  - automatisches Validieren von nutzerdefinierten Constraints in PHP-Syntax (unabhängig vom DBMS)
  - Form-Generator zum Generieren einer grafischen Oberfläche auf Grundlage eines Schemas
  - Reverse-Engineering von Datenbanken in Schema-Dateien
  - Readonly-Flag für Datenbanken, Tabellen und Spalten
- intuitive API mit Query-Builder
- ... der Query-Builder bietet folgende Features:
  - automatisches Quoting von Identifiern und Werten
  - automatisches Erzeugen von Queues für Insert/Update Statements
  - automatisches Caching von Inserts/Updates
  - automatische Kapselung von SQL-Anweisungen in Transaktionen
  - breiter Schutz vor vielen Varianten von SQL-Injections
  - optionaler Bypass zu PEAR-DB
  - Funktion zum Dump der aktuellen Datenbankstruktur in eine Schemadatei
- eigene FlatFile-Datenbank
- ... springt automatisch ein, wenn keine Datenbank zur Verfügung steht oder der Endanwender keine Datenbank benutzen möchte. Damit sind Datenbankfeatures auch auf Servern ohne MySQL-Unterstützung verfügbar. Die FlatFile-Datenbank bietet folgende Features:
  - Unterstützung von Auto-Increment im Stil von MySQL
  - Unterstützung von Transaktionen
  - Read-Stability Isolation Level
  - Funktion zur Synchronisation von Tabellen zwischen einer MySQL-Datenbank und der Flatfile-Datenbank

##### Welche Features werden nicht unterstützt?

Es gibt einige Features welche die FlatFile-Datenbank zur Zeit nicht unterstützt, die aber für eine zukünftige Version geplant sind.

- Unique-Constraint
- Indizes auf Spalten
- Unterstützung von Blobs und Clobs
- Unterstützung von Joins über mehrere Datenbanken
- Random Access für schnelleren Zugriff auf größere Datenbestände

Es gibt einige Features welche in Datenbankschemata zur Zeit nicht unterstützt werden, aber für zukünftige Versionen geplant sind.

- Unterstützung von Triggern / stored Procedures in PHP-Syntax
- Unterstützung von unique constraints
- Unterstützung von unique indices
- Unterstützung von compound primary keys
- Unterstützung von primary keys, die gleichzeitig foreign keys sind

#### Wie erstelle ich eine Verbindung zu einer Datenbank?

Voraussetzung ist eine Schemadatei. Die Schemadateien müssen sich im Verzeichnis "config/db/" befinden und die Dateiendung ".config" besitzen.

##### Um eine Datenbankverbindung mit den aktuellen Verbindungsdaten herzustellen:

global $YANA;
$name_der_strukturdatei = "guestbook";
$datenbankverbdinung = $YANA->connect($name_der_strukturdatei);

Die Verbindungsdaten für die Datenbank (wie Hostadresse, Nutzername und Passwort) werden vom Nutzer im Administrationsmenü eingegeben. Sie müssen diese im Quellcode NICHT angeben.

Wenn Sie keine Strukturdatei verwenden möchten, können Sie diese Angabe frei lassen. Dies wird jedoch in einer Produktionsumgebung nicht empfohlen. In diesem Fall wird das Framework versuchen, die Angaben selbst zu ermitteln. Falls dies fehlschlägt ist die Datenbankverbindung nicht nutzbar.

##### Um eine Datenbankverbindung mit individuellen Verbindungsdaten herzustellen:

Wenn Sie eine Verbindung mit einer Datenbank herstellen, aber die Verbindungsdaten selbst angeben wollen, dann gehen Sie wie folgt vor:

/* Die Verbindungsdaten werden als assoziatives Array angegeben: */
$verbindungsdaten = array(
'DBMS' => 'mysql',
'HOST' => 'localhost',
'PORT' => 0,
'USERNAME' => 'nutzername',
'PASSWORD' => 'passwort',
'DATABASE' => 'name_der_datenbank'
);
/* Um die YANA-API zur Kommunikation mit der Datenbank zu benutzen schreiben Sie: */
$datenbank_server = new DbServer($verbindungsdaten);
$yana_api = new BufferedDbStream($datenbank_server);
/* Um die PEAR-API zur Kommunikation mit der Datenbank zu benutzen schreiben Sie: */
$datenbank_server = new DbServer($verbindungsdaten);
$pear_api = $datenbank_server->get();
/* Um die PEAR-API mit den Standardverbindungsdaten zu benutzen schreiben Sie: */
$datenbank_server = new DbServer();
$pear_api = $datenbank_server->get();

#### Wie prüfe ich, ob im Administrationsmenü die Datenbankverbindung aktiviert ist?

if (YANA_DATABASE_ACTIVE === true) {
print "Datenbank ist aktiviert";
} else if (YANA_DATABASE_ACTIVE === false) {
print "Datenbank ist NICHT aktiviert";
}

#### Wie erstelle ich eine Datenbankabfrage?

Dazu bietet die API die Funktion $db->get(string $key). Diese führt eine Select-Anfrage auf der Datenbank aus und liefert den Wert an der Stelle zurück, welche mit dem Argument $key angegeben wurde.

- Adressiert „key“ einen einzelnen Wert, dann ist der Rückgabewert eine skalare Variable.
- Adressiert „key“ eine Tabelle, dann ist der Rückgabewert ein zweidimensionales assoziatives Datenfeld
- Adressiert „key“ eine Zeile, so ist der Rückgabewert ein eindimensionales assoziatives Datenfeld, wobei die Indizes die Namen der Felder darstellen.
- Adressiert „key“ eine Spalte, so ist der Rückgabewert ein eindimensionales assoziatives Datenfeld, wobei die Indizes die Werte des Pimärschlüssels enthalten.

    global $YANA;
    $db = $YANA->connect("guestbook");

    /*
       Es gilt folgende Syntax:

       $db->get(
                string "$tabelle.$zeile.$spalte",
                string $where,
                string $order_by,
                int $offset,
                int $limit
               );

       Beispiel:
       $value = $db->get("table.1.field","row1=wert1,row2=wert2","order by row1",0,1);

       erzeugt folgende SQL-Anfrage:
       SELECT field from table where primary_key = "1" and row1 like '%wert1%' and row2 like '%wert2%' order by row1 limit 1;
    */

    /* Feld ausgeben */
    $value = $db->get("table.1.field");
    /*
       erzeugt folgende SQL-Anfrage:
       SELECT field from table where primary_key = "1";
    */

    /* Spalte ausgeben: */
    $column = $db->get("table.*.field");
    foreach ($column as $row => $value)
    {
    	print "<p>Value of 'field' in row '$row' = $value</p>";
    }
    /*
       erzeugt folgende SQL-Anfrage:
       SELECT field from table;
    */

    /* Zeile ausgeben: */
    $row = $db->get("table.2");
    foreach ($row as $column => $value)
    {
    	echo "<p>Value of column '$column' in row '2' = $value</p>";
    }
    /*
       erzeugt folgende SQL-Anfrage:
       SELECT * from table where primary_key = "2";
    */

    /* Tabelle ausgeben: */
    $table = $db->get("table");
    foreach ($table as $index => $row)
    {
    	foreach ($row as $column => $value)
    	{
    		echo "<p>Value at 'table.$index.$column' = $value</p>";
    	}
    }
    /*
       erzeugt folgende SQL-Anfrage:
       SELECT * from table;
    */

#### Wie führe ich INSERT- / UPDATE-Statements aus?

Dazu verwenden Sie die Funktion $db->insert($key,$value). Diese fügt den Wert „value“ an der Stelle „key“ ein. Dabei kann es sich entweder um eine Zeile oder eine Tabellenzelle handeln. Das Einfügen von ganzen Tabellen oder Spalten ist nicht möglich.

Beim ersten Aufruf der Funktion wird automatisch eine Transaktion gestartet. Benutzen Sie die Funktion $db->write() um ein COMMIT der Daten auszulösen. Wenn eine der Anweisungen in der Transaktion fehlschlägt, wird automatisch ein CALLBACK ausgeführt.

Falls die Zeile nicht existiert, wird ein die SQL-Anweisung „insert“ benutzt, sonst „update“.

Die Funktion gibt bei Erfolg „true“ zurück und „false“ sonst.

Bitte beachten Sie: die SQL-Anweisung wird erst ausgeführt, wenn die Funktion $db->write() aufgerufen wird.

Im Folgenden einige Beispiele:

    global $YANA;
    $db = $YANA->connect("guestbook");

    /* Neue Zeile einfügen: */
    $db->insert("table.*",array("row1"=>"wert1","row2"=>"wert2"));
    $db->write();

    /* Zeile aktualisieren: */
    $db->insert("table.2",array("row1"=>"wert1","row2"=>"wert2"));
    $db->write();

    /* Zelle aktualisieren: */
    $db->insert("table.2.row1","wert1");
    $db->write();

    /* Transaktion durchführen: */
    $db->insert("table.*",array("row1"=>"wert1","row2"=>"wert2"));
    $db->insert("table.*",array("row1"=>"wert3","row2"=>"wert4"));
    $db->insert("table.1.row3","wert1");
    $db->write();

#### Wie führe ich DELETE-Statement aus?

Dazu verwenden Sie die Funktion $db->remove($key). Diese löscht den Datensatz an der Adresse „key“ aus der Tabelle. Die Funktion gibt bei Erfolg „true“ zurück und „false“ sonst. Es können nur Datensätze gelöscht werden. Keine Tabellen, Zellen oder Spalten.

Beachten Sie folgende Beschränkung: aus Sicherheitsgründen wird pro Aufruf stets maximal 1 Datensatz gelöscht. Wenn Sie mehrere Datensätze löschen wollen, müssen Sie die Funktion mehrmals aufrufen. Diese Einschränkung soll verhindern, dass jemand durch Unachtsamkeit oder aus einem Versehen eine gesamte Tabelle löschen kann.

Bitte beachten Sie: die SQL-Anweisung wird erst ausgeführt, wenn die Funktion $db->write() aufgerufen wird.

    global $YANA;
    $db = $YANA->connect("guestbook");

    /* Die zweite Zeile löschen: */
    $db->remove("table.2");
    $db->write();
    /*
       erzeugt folgende SQL-Anfrage:
       DELETE FROM table WHERE primary_key = "2" LIMIT 1;
     */

    /* Die ganze Tabelle "table" löschen: */
    for ($i=0; $i < $db->length($table); $i++)
    {
    	$db->remove("table.*");
    }
    $db->write();
    /*
       erzeugt folgende SQL-Anfrage:
       DELETE FROM table WHERE primary_key = "2" LIMIT 1;
     */

#### Wie finde ich heraus wie viele Datensätze eine Tabelle hat?

    global $YANA;
    $db = $YANA->connect("guestbook");

    if ($db->length("table") === 0) {
    	print "Die Tabelle 'table' ist leer.";
    } else {
    	print "Die Tabelle 'table' enthält ".$db->length("table")." Datensätze.";
    }

#### Wie finde ich heraus ob eine Tabelle / Datensatz existiert?

    global $YANA;
    $db = $YANA->connect("guestbook");

    /* Datenbankverbindung prüfen: */
    if ($db->exists() === true) {
    	print "Die Datenbankverbindung ist verfügbar.";
    } else if ($db->exists() === false) {
    	print "Die Datenbankverbindung ist NICHT verfügbar";
    }

    /* Prüfen ob Tabelle existiert: */
    if ($db->exists("table") === true) {
    	print "Die Tabelle 'table' existiert.";
    } else if ($db->exists("table") === false) {
    	print "Es gibt keine Tabelle mit dem Namen 'table'.";
    }

    /* Prüfen ob Datensatz existiert: */
    if ($db->exists("table.2") === true) {
    	print "Der Datensatz '2' in der Tabelle 'table' existiert.";
    } else if ($db->exists("table.2") === false) {
    	print "Es gibt keinen Datensatz '2' in der Tabelle 'table'.";
    }

    /* Prüfen ob Feld existiert und einen Wert hat: */
    if ($db->exists("table.2.field") === true) {
    	print "Das Feld 'field' im Datensatz '2' in Tabelle 'table' hat einen Wert.";
    } else if ($db->exists("table.2.field") === false) {
    	print "Das Feld 'field' im Datensatz '2' in Tabelle 'table' existiert nicht oder ist NULL.";
    }

    /* Prüfen ob mindestens 1 Feld existiert, dass NOT NULL ist: */
    if ($db->exists("table.*.field") === true) {
    	print "Die Spalte 'field' in Tabelle 'table' existiert.";
    } else if ($db->exists("table.*.field") === false) {
    	print "Die Spalte 'field' in Tabelle 'table' existiert nicht oder alle Werte sind NULL.";
    }

#### Wie erstelle ich eine Installationsroutine für meine Tabellen?

YANA hat eine Installationsroutine für Datenbanken, welche Sie im Administrationsmenü, in der Basiskonfiguration im Menü "Datenbank Setup" finden. Über dieses Menü kann ein Nutzer alle Tabllen installieren oder Inhalte zwischen dem DBMS und der FlatFile-Datenbank synchronisieren.

Sie können diese Installationsroutine mit eigenen Einträgen "bestücken". Kopieren Sie dazu Ihr Datenbankschema in das Verzeichnis "config/db/". Die SQL-Dateien mit den erforderlichen DDL-Statements für jedes DBMS, welches Sie unterstützen wollen, speichern Sie im Verzeichnis "config/db/.install/". Dort finden Sie verschiedene Unterverzeichnisse für verschiedene Datenbankhersteller, in welchen Sie Ihre Installationsdateien ablegen können. Sie finden dort außerdem eine Datei "readme.txt", welche eine Liste der unterstützten DBMS und den Namen der Verzeichnisse enthält.

Selbstverständlich sollten Sie Ihre SQL-Dateien stets mit dem jeweiligen DBMS testen, bevor Sie diese veröffentlichen ;-)

Für zukünftige Versionen ist geplant, die erforderlichen DDL-Statements direkt aus dem Schema der Datenbank zu generieren. Die SQL-Dateien wären dann nur noch eine optionale Ergänzung.

#### Wie importiere ich eine SQL-Datei mit DDL-Anweisungen?

    global $YANA;
    $db = $YANA->connect("guestbook");

    $db->importSQL('data.sql');

#### Wie exportiere ich Daten in eine CSV-Datei?

    global $YANA;
    $db = $YANA->connect("guestbook");

    $csv = $db->toString("table");
    file_put_contents("table.csv", $csv);

#### Wie exportiere ich ein Datenbankschema in eine Datei?

    global $YANA;
    $db = $YANA->connect("guestbook");

    $db->exportStructure("guestbook.config");

#### Wie schreibe ich ein eigenes Datenbankschema?

Schema-Dateien haben die Endung "*.config" und werden im Verzeichnis "config/db/" gespeichert. Eine Verbindung auf Grundlage einer Schema-Datei wird hergestellt über den PHP-Code: $YANA->connect("Name der Datei ohne Dateiendung");

Das folgende Listing zeigt ein Schema mit allen Elementen und alle gültigen Belegungen. Existieren mehrere mögliche Varianten, dann sind diese die verschiedenen Möglichkeiten durch eine Pipe '|' voneinander getrennt. Bezeichner, die frei gewählt werden können, sind im Text fett hervorgehoben.

    /* Das Feld "USE_STRICT" legt fest, ob Queries zur Laufzeit
     * gegen das Schema validiert werden oder nicht.
     */
    <USE_STRICT>true|false</USE_STRICT>

    /* Das Feld "READONLY" ist optional. Default = false
     */
    <READONLY>true|false</READONLY>

    /* Constraints sind boolsche Ausdrücke in PHP-Syntax.
     * Sie können mit einer bestimmten SQL-Aktion verknüpft werden.
     * Ergibt der Ausdruck "false" wird die entsprechende Query nicht
     * abgeschickt und ein Log-Eintrag geschrieben. Andernfalls wird die
     * Aktion fortgesetzt.
     *
     * In Constraints können Sie keine Funktionen aufrufen, mit einer einzigen
     * Ausnahme: preg_match();
     * Außerdem haben Sie Zugriff auf folgende Konstanten:
     * $VALUE      = (für INSERT, UPDATE) Wert der eingefügt wird
     * $PERMISSION = Zugriffslevel des Nutzers, der die Aktion ausgelöst hat
     * $OPERATION  = SQL-Kommando das gerade durchgeführt wird (SELECT, INSERT, ...)
     * $TABLE      = Name der Zieltabelle (meist die aktuelle Tabelle)
     * $FIELD      = Name der Zielspalte (falls angegeben)
     *
     * Beispiele:
     * <SELECT>true</SELECT>
     * <UPDATE>false</UPDATE>
     * <UPDATE>$VALUE > 0 && $VALUE < 500</UPDATE>
     * <INSERT>$PERMISSION > 50</INSERT>
     * <INSERT>preg_match('/^[\w\d-_]*$/i', $VALUE)</INSERT>
     *
     * Constraints gibt es in YANA seit Version 2.8 .
     */
    <CONSTRAINT>
    	<SELECT>PHP-Code</SELECT>
    	<INSERT>PHP-Code</INSERT>
    	<UPDATE>PHP-Code</UPDATE>
    	<DELETE>PHP-Code</DELETE>
    </CONSTRAINT>

    /* Wie Sie vielleicht schon vermutet haben: die Option READONLY=true
     * und der Constraint UPDATE=false haben beide den gleichen Effekt.
     */

    /* Hier folgt die Definition der Tabellen.
     */
    <TABLES>
    	<Name der Tabelle>
    		<READONLY>true|false</READONLY>

    		<CONSTRAINT>
    			<SELECT>PHP-Code</SELECT>
    			<INSERT>PHP-Code</INSERT>
    			<UPDATE>PHP-Code</UPDATE>
    			<DELETE>PHP-Code</DELETE>
    		</CONSTRAINT>

    /* Im Feld "PRIMARY_KEY" ist der Name der Spalte anzugeben, welche den Primärschlüssel enthält.
     */
    		<PRIMARY_KEY>Name der Spalte</PRIMARY_KEY>

    /* Im Feld "FOREIGN_KEY" kann eine Liste von Fremdschlüsseln angegeben werden.
     */
    		<FOREIGN_KEY>
    			<Name der Zieltabelle>Name der Spalte</Name der Zieltabelle>
    			<andere Zieltabelle>andere Spalte</andere Zieltabelle>
    		</FOREIGN_KEY>

    /* Hier folgt die Definition der Tabellenspalten.
     */
    		<CONTENT>
    			<Name der Spalte>
    				<READONLY>true|false</READONLY>

    				<CONSTRAINT>
    					<SELECT>PHP-Code</SELECT>
    					<INSERT>PHP-Code</INSERT>
    					<UPDATE>PHP-Code</UPDATE>
    					<DELETE>PHP-Code</DELETE>
    				</CONSTRAINT>

    /* Im Feld "DESCRIPTION" kann ein Beschriftung für diese Spalte angegeben werden.
     * Sie können hier auch %TOKEN% verwenden, welche Sie zum Beispiel in Ihrem Programm,
     * oder als Sprachdatei festlegen, um eine Beschriftung in mehreren Sprachen anbieten
     * zu können.
     */
    				<DESCRIPTION>Label der Spalte</DESCRIPTION>

    /* Die primitiven, skalaren Datentypen "integer", "float" und "string"
     * entsprechen ihrem Äquivalent in PHP. Zusätzlich wurden weitere nützliche Datentypen
     * eingeführt.
     * mail    = prüft beim Eintragen automatisch, ob der Wert eine gültige Mailadresse ist
     * ip      = prüft beim Eintragen automatisch, ob der Wert eine gültige IP-Adresse ist
     * text    = für Eingaben aus Textarea-Feldern, führt automatisch zusätzliche Prüfungen
     *           zum Schutz vor Flooding durch
     * select  = ein Aufzählungsdatentyp, dessen Elemente im Feld "DEFAULT" definiert werden,
     *           siehe unten.
     * array   = kann verwendet werden, um PHP-Arrays zu speichern. Diese werden beim Auslesen
     *           des Wertes aus der Datenbank automatisch wieder umgewandelt.
     */
    				<TYPE>integer|float|string|text|url|ip|mail|time|select|array</TYPE>

    				<LENGTH>positive integer</LENGTH>

    /* Das Feld "REQUIRED" legt fest ob ein Feld NULLABLE ist oder nicht.
     */
    				<REQUIRED>true|false</REQUIRED>

    /* Das Feld "DEFAULT" legt einen Wert fest, der automatisch verwendet wird, wenn beim
     * Anlegen des Datensatzes keine anderen Angaben gemacht werden.
     */
    				<DEFAULT>ein Defaultwert</DEFAULT>

    /* Die Anweisungen für die GUI und das SDK können im Feld "DISPLAY" angegeben werden.
     * Dazu existieren jeweils zwei Einstellungen: "HIDDEN" und "READONLY".
     * Wobei "READONLY" bedeutet, dass diese Spalte nicht zum Editieren angezeigt werden soll.
     * Wie der Name schon sagt, bedeutet "HIDDEN", dass die Spalte in der Ausgabe gar nicht
     * auftauchen soll.
     * Es gibt jeweils eine Einstellung, für die Abfragen: "NEW", "EDIT", "VIEW" und "SEARCH".
     * Die Eigenschaften können jeweils global oder für jede Aktion einzeln gesetzt werden.
     */

    /* Zunächst die Variante mit globalen Einstellungen
     */
    				<DISPLAY>
    					<HIDDEN>true|false</HIDDEN>
    					<READONLY>true|false</READONLY>
    				</DISPLAY>

    /* Nun die Variante mit lokalen Einstellungen für jede Option
     */
    				<DISPLAY>
    					<HIDDEN>
    						<NEW>true|false</NEW>
    						<EDIT>true|false</EDIT>
    						<SELECT>true|false</SELECT>
    						<SEARCH>true|false</SEARCH>
    					</HIDDEN>
    					<READONLY>
    						<NEW>true|false</NEW>
    						<EDIT>true|false</EDIT>
    					</READONLY>
    				</DISPLAY>
    			</Name der Spalte>

    /*
     * Für die Datentypen integer, ip und time kann für das Feld "REQUIRED" der Wert "AUTO"
     * gesetzt werden. Dies bedeutet, dass der Wert automatisch erzeugt wird.
     * Für time    = das aktuelle Datum als Unix-Timestamp
     * Für ip      = die IP des Besuchers
     * Für integer = autoincrement beziehungsweise der Wert einer Sequence
     */
    			<Name der Spalte>
    				<TYPE>integer|ip|time</TYPE>
    				<REQUIRED>AUTO</REQUIRED>
    			</Name der Spalte>

    /*
     * Für den Datentyp select kann eine Aufzählung der erlaubten Werte angegeben werden.
     *
     * Die Semantik kann man sich relativ leicht merken:
     * + Die GUI stellt Spalten vom Typ select in Formularen als Select-Feld dar.
     * + Die Darstellung im Schema erinnert ebenfalls an ein Select-Formularfeld in HTML.
     */
    			<Name der Spalte>
    				<TYPE>select</TYPE>
    				<DEFAULT>
    					<defaultwert>Beschriftung</defaultwert>
    					<option 1>Beschriftung 1</option 1>
    					<option 2>Beschriftung 2</option 2>
    				</DEFAULT>
    			</Name der Spalte>

    		</CONTENT>
    	</Name der Tabelle>

    /* Hier können weitere Tabellen folgen.
     */

    </TABLES>

Im Folgenden ein Beispiel für eine Datenbank. Dargestellt ist die Datenstruktur der Gästebuch-Anwendung:

    <USE_STRICT>true</USE_STRICT>
    <READONLY>false</READONLY>
    <TABLES>
    	<guestbook>
    		<PRIMARY_KEY>guestbook_id</PRIMARY_KEY>
    		<CONTENT>
    			<guestbook_id>
    				<TYPE>integer</TYPE>
    				<LENGTH>5</LENGTH>
    				<DEFAULT>Id (PK)</DEFAULT>
    				<DISPLAY>
    					<HIDDEN>true</HIDDEN>
    				</DISPLAY>
    			</guestbook_id>
    			<profile_id>
    				<TYPE>string</TYPE>
    				<LENGTH>128</LENGTH>
    				<REQUIRED>AUTO</REQUIRED>
    				<DEFAULT>Id (FK)</DEFAULT>
    				<DISPLAY>
    					<HIDDEN>true</HIDDEN>
    				</DISPLAY>
    			</profile_id>
    			<guestbook_ip>
    				<TYPE>ip</TYPE>
    				<LENGTH>15</LENGTH>
    				<REQUIRED>AUTO</REQUIRED>
    				<DISPLAY>
    					<HIDDEN>true</HIDDEN>
    				</DISPLAY>
    			</guestbook_ip>
    			<guestbook_name>
    				<TYPE>string</TYPE>
    				<LENGTH>128</LENGTH>
    				<REQUIRED>true</REQUIRED>
    				<DESCRIPTION>Name</DESCRIPTION>
    			</guestbook_name>
    			<guestbook_message>
    				<TYPE>text</TYPE>
    				<LENGTH>3000</LENGTH>
    				<REQUIRED>true</REQUIRED>
    				<DESCRIPTION>Text</DESCRIPTION>
    			</guestbook_message>
    			<guestbook_mail>
    				<TYPE>mail</TYPE>
    				<LENGTH>255</LENGTH>
    				<DESCRIPTION>Mail</DESCRIPTION>
    			</guestbook_mail>
    			<guestbook_homepage>
    				<TYPE>string</TYPE>
    				<LENGTH>512</LENGTH>
    				<DESCRIPTION>Homepage</DESCRIPTION>
    			</guestbook_homepage>
    			<guestbook_messenger>
    				<DESCRIPTION>Messenger</DESCRIPTION>
    				<TYPE>string</TYPE>
    				<LENGTH>255</LENGTH>
    			</guestbook_messenger>
    			<guestbook_msgtyp>
    				<DESCRIPTION>Typ</DESCRIPTION>
    				<TYPE>select</TYPE>
    				<LENGTH>5</LENGTH>
    				<DEFAULT>
    					<icq>ICQ</icq>
    					<aol>AOL</aol>
    					<yahoo>Yahoo!</yahoo>
    					<msn>MSN</msn>
    				</DEFAULT>
    			</guestbook_msgtyp>
    			<guestbook_opinion>
    				<TYPE>select</TYPE>
    				<LENGTH>1</LENGTH>
    				<CONSTRAINT>
    					<INSERT>$VALUE >= 0 && $VALUE <= 5</INSERT>
    					<UPDATE>$VALUE >= 0 && $VALUE <= 5</UPDATE>
    				</CONSTRAINT>
    				<DEFAULT>
    					<0>unentschlossen</0>
    					<1>sehr gut</1>
    					<2>gut</2>
    					<3>befriedigend</3>
    					<4>ausreichend</4>
    					<5>ungenügend</5>
    				</DEFAULT>
    				<DESCRIPTION>Meinung</DESCRIPTION>
    			</guestbook_opinion>
    			<guestbook_date>
    				<TYPE>time</TYPE>
    				<REQUIRED>AUTO</REQUIRED>
    				<DESCRIPTION>Datum/Zeit</DESCRIPTION>
    				<DISPLAY>
    					<HIDDEN>
    						<NEW>true</NEW>
                        			</HIDDEN>
    				</DISPLAY>
    			</guestbook_date>
    			<guestbook_comment>
    				<TYPE>text</TYPE>
    				<LENGTH>1024</LENGTH>
    				<REQUIRED>false</REQUIRED>
    				<DESCRIPTION>Kommentar</DESCRIPTION>
    				<DISPLAY>
    					<READONLY>
    						<EDIT>true</EDIT>
    					</READONLY>
    				</DISPLAY>
    			</guestbook_comment>
    			<guestbook_is_registered>
    				<TYPE>integer</TYPE>
    				<LENGTH>1</LENGTH>
    				<REQUIRED>AUTO</REQUIRED>
    				<DEFAULT>0</DEFAULT>
    				<DISPLAY>
    					<HIDDEN>true</HIDDEN>
    				</DISPLAY>
    			</guestbook_is_registered>
    		</CONTENT>
    	</guestbook>
    </TABLES>

### Dateisystem

#### Wie erhalte ich den Inhalt von Verzeichnissen?

Die Funktion dirlist() liefert für ein Verzeichnis eine sortierte Liste der enthaltenen Dateien und Verzeichnisse als numerisches Datenfeld zurück. Die obligatorischen Verzeichniseinträge „.“ und „..“ werden nicht aufgelistet. Dateien, deren Dateinamen mit dem Zeichen „.“ beginnen werden ebenfalls nicht aufgelistet. Das betrifft insbesondere Dateinamen wie „.htaccess“ oder „.password“. Die Dateinamen enthalten keine Pfadangaben. Verzeichnisnamen enthalten keinen abschließenden Querstrich „/“.

Der optionale Parameter $filter kann verwendet werden um die Ausgabe auf bestimmte Dateiendungen zu beschränken. Wildcards sind nicht gestattet. Der Dateifilter darf lediglich alphanumerische Zeichen, sowie die Zeichen '.', '-' und '_' enthalten. Andere Zeichen werden beim Aufruf der Funktion automatisch entfernt.

    /* alle Einträge eines Verzeichnisses ausgeben */
    echo implode("<br>", dirlist("foo/"));

    /*
     Ausgabe:
    foo1.foo2
    foo3.foo2
    foo4.foo5
    foo6.foo7
    */

    /* alle Einträge mit passender Dateiendung ausgeben */

    echo implode("<br>", dirlist('foo/', '*.foo2'));

    /*
     Ausgabe:
    foo1.foo2
    foo3.foo2
    */

    /* ... mit mehreren Dateiendungen */

    echo implode("<br>", dirlist('foo/', '*.foo2|*.foo5'));

    /*
     Ausgabe:
    foo1.foo2
    foo3.foo2
    foo4.foo5
    */

    /* objektorientierte Variante */
    $dirStream = new DirStream("foo/");
    $dirStream->read();
    $dirlist = $dirStream->dirlist('*.foo2|*.foo5');
    echo implode("<br>", $dirlist);

    /* Hinweis: das Setzen des Dateifilters ist permanent. */

    $dirStream->dirlist('*.foo2|*.foo5');
    echo $dirStream->length();
    /* Ausgabe: 2 */

    echo count($dirStream->get());
    /* Ausgabe: 2 */

    /* Ein erneuter Aufruf von dirlist() setzt den Dateifilter neu */
    $dirStream->dirlist("");
    echo $dirStream->length();
    /* Ausgabe: 4 */

#### Wie kann ich Verzeichnisse anlegen oder löschen?

Die Funktionen $dirStream->create($mode) beziehungsweise $dirStream->delete() sind für Erzeugen beziehungsweise Löschen von Verzeichnissen verantwortlich. Der optionale Parameter $mode kann verwendet werden, um unter LINUX/UNIX -Betriebssystemen Zugriffsrechte von Verzeichnissen festzulegen. Der Defaultwert ist 777.

Beispiele für gültige Werte für $mode finden Sie in der folgenden Tabelle. Dabei steht „r“ für „readable“, „w“ für „writeable“ und „x“ für „executeable“.

Besitzer | Gruppe | sonstige Nutzer | Wert
--- | --- | --- | ---
rwx | rwx | rwx | 777
rw- | rw- | --- | 660
rw- | rw- | rw- | 666
rwx | r-x | r-x | 755
rwx | r-x | --- | 750
rwx | --- | --- | 700

Beispiele für gültige Werte (entsprechend Unix: CHMOD)

    $dirStream = new DirStream("foo/");
    $dirStream->read();

    /* erzeuge das Verzeichnis "foo/" */
    $dirStream->create();

    /* erzeuge das Verzeichnis "foo/" mit Zugriffsrechten 660 */
    $dirStream->create(660);

    /* Anzahl der Dateien in einem Verzeichnis feststellen */
    print "Verzeichnis 'foo/' enthält ".$dirStream->length()." Dateien.";

    /* lösche das Verzeichnis "foo/" */
    $dirStream->delete();

    /* lösche das Verzeichnis "foo/" inklusive aller Dateien und Unterverzeichnisse */
    $dirStream->delete(true);

    /* prüfe ob Verzeichnis existiert */
    $test = $dirStream->exists();
    if ($test === true) {
    	print "Verzeichnis existiert";
    } else if ($test === false) {
    	print "Verzeichnis existiert NICHT";
    }

#### Wie lese ich den Inhalt einer Config- oder SML-Datei?

Die Funktion getConfigFile() lädt die angegebene Konfigurationsdatei im SML-Format und liefert den Inhalt als PHP-Variable zurück.

    /* Lies Inhalte von Datei und gib Inhalte als Array zurück */
    $array = getConfigFile("foo.config");

    /* Schlüssel in Großbuchstaben (default) */
    $array = getConfigFile("foo.config", CASE_UPPER);

    /* Schlüssel in kleinen Buchstaben */
    $array = getConfigFile("foo.config", CASE_LOWER);

    /* Schlüssel in gemischter Schreibweise */
    $array = getConfigFile("foo.config", CASE_MIXED);

    /* objektorientierte Variante, gemischte Schreibweise */
    $configFile = new ConfigFile("foo.config");
    $configFile->read();
    $array = $configFile->get();

    /* objektorientierte Variante, Schlüssel in Großbuchstaben */
    $smlFile = new SmlFile("foo.config");
    $smlFile->read();
    $array = $smlFile->get();

    /* Navigieren innerhalb einer SML-Datei

    Angenommen die Datei "foo.config" hätte folgenden Inhalt:

    <ROOT>
    	<FOO1>
    		<FOO2>text</FOO2>
    		<FOO3>
    			<0>1</0>
    			<1>foo</1>
    		</FOO3>
    	</FOO1>
    </ROOT>

    */

    $mixed = $smlFile->get("ROOT.FOO1");
    print_r($mixed);

    /*
     Diese Abfrage liefert den Teilbaum ROOT.FOO1 mit FOO1 als Wurzelement.
     Ausgabe:

    array(
    	"FOO2" => "text",
    	"FOO3" => array (
    		0 => 1,
    		1 => "foo"
    	)
    )

    */

#### Wie schreibe ich eine Variable in eine Config- oder SML-Datei?

Die Funktion makeConfig() erzeugt für die übergebene Variable eine Darstellung als SML-Code und liefert diesen als String zurück. Es muss sich entweder um eine Variable mit einem skalaren Wert oder ein Array handeln.

Bitte beachten Sie: die Funktion „makeConfig“ erkennt keine unendlichen Rekursionen. Daher müssen die Datenfelder rekursionsfrei sein. Andernfalls wird durch den Compiler eine Fehlermeldung erzeugt.

    /* Speichert die Einträge eines Array in der Datei "foo.config" */
    $string = makeConfig($array, "ROOT");
    file_put_contents("foo.config", $string);

    /* ersetzen Sie "ROOT" durch den Namen des Wurzelelements */

    /* Benutzen von Großbuchstaben, Kleinbuchstaben und gemischter Schreibweise analog zu getConfigFile() */
    $string = makeConfig($array, "ROOT", CASE_UPPER); // groß (default)
    $string = makeConfig($array, "ROOT", CASE_LOWER); // klein
    $string = makeConfig($array, "ROOT", CASE_MIXED); // gemischt

    /* objektorientierte Variante, gemischte Schreibweise */
    $configFile = new ConfigFile("foo.config");
    $configFile->read();
    $configFile->create();
    $configFile->insert($string);
    $configFile->write();

    /* objektorientierte Variante, Schlüssel in Großbuchstaben */
    $smlFile = new SmlFile("foo.config");
    $smlFile->read();
    $smlFile->create();
    $smlFile->insert($string);
    $smlFile->write();

### Besucherzähler und Statistiken

#### Wie erstelle ich einen Zähler?

Das YANA bietet die Möglichkeit persistente Zählervariablen, also solche deren Wert automatisch gespeichert wird, zu verwenden.

Es gibt zwei Arten von Zählervariablen: solche, die mit IP-Check, welche nur dann zählen, wenn der Nutzer mit der aktuellen IP nicht innerhalb der letzten 3 Stunden eine Veränderung des Zählers bewirkt hat. Und solche ohne IP-Check, welche stets weiter zählen wenn Sie aufgerufen werden.

Im Folgenden einige Beispiele.

    /* Erzeuge einen Zähler mit IP-Check */
    $counter = new Counter("meine_statistiken", YANA_COUNTER_USE_IP);
    /* ... oder auch: */
    $counter = new Counter("meine_statistiken");

    /* Erzeuge einen Zähler ohne IP-Check */
    $counter = new Counter("meine_statistiken", YANA_COUNTER_IGNORE_IP);

    /* Den Zähler "test1" um 1 erhöhen */
    $counter->count("test1");
    /* Den Zähler "test2" um 1 erhöhen und eine Beschreibung der Änderung speichern */
    $counter->count("test2", "Bewertung");

    /* Den Zähler "test1" um 3 erhöhen */
    $counter->count("test1", "Bewertung", 3);

    /* Den Zähler "test1" um 2 verringern */
    $counter->count("test1", "Bewertung", -2);

#### Wie frage ich den Zählerstand ab?

    $counter = new Counter("meine_statistiken");

    /* Den Zählerstand von "test1" abfragen */
    $int = $counter->getCount("test1");

    /* Die Beschreibung von Zähler "test1" abfragen */
    $string = $counter->getInfo("test1");

    print $string.":\t".$int;
    /*
      Ausgabe
      Bewertung:	2
    */

    /* Alle Zähler abfragen */
    $array = $counter->getCount("*");
    foreach ($array as $a => $b) print $a.":\t".$b;

#### Wie erzeuge ich einen grafischen Besucherzähler?

    /* In der Template-Datei fügen Sie folgendes ein: */
    <img src=[%"action=graphic_counter&target=0"|href%]>

Mit dem Parameter "target" wählen Sie die Grafik aus. Gültige Werte sind die Zahlen 0-6.

Wert für Target | Darstellung
--- | ---
0 |
1 |
2 |
3 |
4 |
5 |
6 |

### E-Mails versenden

Versionsinformation: Die Funktionen send_mail und form_mail, sowie die Klasse form_mailer wurden in Version 2.8 umbenannt in sendMail, formMail und formMailer, um der Namenskonvention des Frameworks zu entsprechen. Die Funktion sendMail ist ab Version 2.8 eine statische Funktion der Klasse Mailer. Die Funktion formMail ist ab Version 2.8 eine statische Funktion der Klasse FormMailer.

#### Allgemeines zum Versand von Mails

YANA bietet die Funktion Mailer::mail() zum Versand von Mails, welche Reihe von Sicherheitsvorkehrungen implementiert, welche vor verschiedenen Arten von Header-Injection schützen.

Die Funktion „Mailer::mail“ ist eine gegen Missbrauch und „Header-Injection“ abgesicherte Variante der nativen PHP-Funktion „mail“. Anders als „mail“ werden alle Eingabedaten geprüft und auch nicht alle Header-Informationen, welche „mail“ prinzipiell gestattet sind erlaubt.

Es wird „true“ zurückgegeben, wenn die Mail versandt werden konnte, „false“ sonst. Der Wert „true“ bedeutet jedoch nicht, dass die Mail erfolgreich zugestellt wurde. Er bedeutet lediglich, dass die Eingabedaten im Sinne dieser Funktion syntaktisch korrekt waren.

Die Funktion erzeugt im Header der Mail die zusätzlichen Einträge „x-yana-php-header-protection“ und „x-yana-php-spam-protection“.

- „x-yana-php-header-protection“ hat den Wert 0 wenn der übergebene Header unauffällig war, andernfalls 1
- „x-yana-php-spam-protection“ hat den Wert 0 wenn der Header kein bcc-Feld enthielt, sonst 1

Wenn Sie eine Mail empfangen, die über YANA versendet wurde, können Sie im Header der Mail die entsprechenden Einträge prüfen, um zu sehen ob das Framework im Nachrichtentext Unregelmäßigkeiten entdeckt hat.

bool Mailer::mail(string $recipient, string $subject, string $text [, array $header ] )

Aus Sicherheitsgründen gelten folgende Einschränkungen.

- Empfänger: $recipient
  Der Parameter muss eine gültige Mailadresse sein gemäß des regulären Ausdrucks (Perl-Syntax)
  /^[äöüß\w\d-_\.]{1,}\@[äöüß\w\d-_\.]{2,}\.[\w\d-_\.]{2,}$/i

- Betreff: $subject
  Alle Sonderzeichen außer „()äÄüÜöÖß[]“, alle Tags sowie alle Zeilenumbrüche werden still (ohne Warnung) entfernt. Bei einer Länge von mehr als 128 Zeichen werden alle nachfolgenden Zeichen still entfernt.

- Nachrichtentext: ($text)
  Alle '@'-Zeichen werden still durch die Zeichenkette „[at]“ ersetzt. Bei Textnachrichten erfolgt ein automatischer Zeilenumbruch nach 70 spätestens Zeichen. Bei HTML-Nachrichten werden einige potentiell gefährliche Tags still entfernt (Blacklist-Ansatz).

- Header: $header
  Dieser Parameter ist ein assoziatives Datenfeld. Es darf beliebige X-Header-Daten enthalten, sowie einige unkritische Header-Informationen (Whitelist-Ansatz).

Die Liste der von Header akzeptierten Parameter lautet:

Parameter | Typ | Default | Beschreibung
--- | --- | --- | ---
from | mail | n/a | Eine gültige Mailadresse
return-path | mail | n/a | Eine gültige Mailadresse
cc | mixed | n/a | Entweder eine gültige Mailadresse oder ein numerisches Datenfeld mit mehreren Mailadressen. An alle angegebenen Adressen wird eine Kopie der Nachricht versandt. Anders als bei „bcc“ ist die Liste der Empfänger jedoch für alle Empfänger sichtbar.
content-type | string | text/plain; charset="8859-1" | Bestimmt den MIME-Type der Nachricht. Nur MIME-Type und Charset sind als Eingaben erlaubt. Andere Werte werden ignoriert.
mime-version | float | 1.0 | Angabe muss entsprechend folgendes regulären Ausdrucks erfolgen (Perl-Syntax): /^\d\.\d$/
content-transfer-encoding | string | n/a | Angabe muss entsprechend folgendes regulären Ausdrucks erfolgen (Perl-Syntax): /^\d{,2}bit$/i

gültige Werte für Parameter header Funktion Mailer::mail

Die Verwendung von „BCC“ ist aus Sicherheitsgründen nicht gestattet.

#### Wie sende ich einen Text als Mail?

$recipient = "meineMail@domain.tld";
$subject = "Benachrichtigung";
$text = "Du hast einen neuen Eintrag!\nSchau mal wieder vorbei.";
$header = array("cc" => "andereMail@domain.tld");
$test = Mailer::mail($recipient, $subject, $text, $header);
if ($test === true) {
print "Versand erfolgreich";
} else if ($test === false) {
print "Versand nicht erfolgreich";
}

#### Wie sende ich eine Mail auf Basis eines Templates?

/* Das Template "beispiel.mail" könnte wie folgt aussehen */
Hallo [%$NAME%]!
Jemand hat dir eine Nachricht hinterlassen, sie lautet:
[%$NACHRICHT%]
IP des Besuchers: [%$IP%]
/* Dies ist der Quelltext zum Versenden der Mail: */
$recipient = "meineMail@domain.tld";
$subject = "Benachrichtigung";
$mailer = new Mailer("skins/mein_skin/beispiel.mail");
$mailer->subject = $subject;
$mailer->sender = $ARGS["mail"];
$mailer->insert("NAME", $ARGS["name"]);
$mailer->insert("NACHRICHT", $ARGS["nachricht"]);
$mailer->insert("IP", $_SERVER["REMOTE_ADDR"]);
$test = $mailer->send($recipient);
if ($test === true) {
print "Versand erfolgreich";
} else if ($test === false) {
print "Versand nicht erfolgreich";
}
/* Eine versendete Mail könnte dann wie folgt aussehen: */
Hallo Thomas!
Jemand hat dir eine Nachricht hinterlassen, sie lautet:
Hallo Welt
IP des Besuchers: 127.0.0.1

Anmerkung: vor dem Versand der E-Mail prüft die Funktion $mailer->send() die Eingabedaten automatisch auf Versuche von Header-Injection und säubert alle Eingaben. Es kann jedoch absolut nichts schaden, wenn Sie die Syntax der Eingabedaten trotzdem auch in Ihrem Skript noch einmal überprüfen bevor Sie die Funktion aufrufen.

#### Wie versende ich Daten aus einem Formular als Mail?

/* Dies ist der Quelltext zum Versenden der Mail: */
$recipient = "meineMail@domain.tld";
$subject = "Benachrichtigung";
$headline = "Inhalte des Kontaktformulars:\n\n";
$footline = "\n\nYANA formmailer at ".$_SERVER['SERVER_NAME'];
$formMailer = new Mailer("skins/mein_skin/beispiel.mail");
$formMailer->subject = $subject;
$formMailer->content = $formulardaten;
$formMailer->headline = $headline;
$formMailer->footline = $footline;
$test = $formMailer->send($recipient);
if ($test === true) {
print "Versand erfolgreich";
} else if ($test === false) {
print "Versand nicht erfolgreich";
}
/* Eine versendete Mail könnte dann wie folgt aussehen: */
Inhalte des Kontaktformulars:
==========================================
Benachrichtigung
==========================================
name: Walter
alter: 35
betreff: Neueintrag
dringend: [x]
nachricht: Bitte Passwort senden!
==========================================
Datum: 11.08.2006 10:06:41
IP: 127.0.0.1
YANA formmailer at foo.server.tld

### Formulardaten prüfen

#### Wie kann ich Nutzereingaben vor der Verarbeitung säubern?

Zu diesem Zweck bietet Ihnen YANA die Funktion untaintInput().

Die Funktion verfügt über folgende Parameter:

Parameter | Typ | Default | Beschreibung
--- | --- | --- | ---
value | mixed | n/a | zu säuberndes Datum
type | string | „“ | Datentyp Neben den von PHP unterstützten nativen Typen sind noch folgende Werte erlaubt: time: UTC-Zeitcode (Typ Integer, Länge 11) ip: IP-Adresse (Typ String, Länge 15) mail: Mailadresse (Typ String) select: wird behandelt wie „string“ text: wird behandelt wie „string“
length | integer | 0 | Maximale Länge des Datums
escape | integer | 0 | siehe Tabelle

Parameterliste untaintInput

Der Parameter $escape kann mit einer der folgenden Konstanten belegt werden.

Bezeichner | Beschreibung
--- | ---
YANA_ESCAPE_NONE | keine Änderungen durchführen (Default)
YANA_ESCAPE_SLASHED | wandelt einfache und doppelte Anführungszeichen in ihre entsprechenden Escapesequenzen in C-Syntax um
YANA_ESCAPE_TOKEN | ersetzt enthaltene Token durch ihre HTML-Entities
YANA_ESCAPE_CODED | ersetzt HTML-Symbole, beispielsweise Tagklammern, durch Entities
YANA_ESCAPE_LINEBREAK | wandelt alle Whitespace-Zeichen (insbesondere Zeilenumbrüche) in Leerzeichen um
YANA_ESCAPE_USERTEXT | zur Behandlung von Text aus Textarea-Feldern

Gültige Belegungen für den Parameter $escape der Funktion untaintInput

Für INPUT-Felder sollten Sie stets die Funktion untaintInput() mit dem Parameter YANA_ESCAPE_LINEBREAK aufrufen. Das verhindert, dass ein Angreifer Zeilenumbrüche in Ihre Ausgabe schmuggelt. Für TEXTAREA-Felder sollten Sie den Parameter YANA_ESCAPE_USERTEXT verwenden. Dieser verhindert viele Formen von Flooding, indem Zeichenfolgen die sich ständig wiederholen (Copy'n'Paste Flooding) entfernt werden, oder zum Beispiel ellenlange Texte oder Leerzeichen nach einer bestimmten Anzahl von Leerzeichen per Zwang umgebrochen werden, um das Layout Ihrer Seite nicht zu zerstören.

### Log-Dateien und Fehlermeldungen

#### Wo finde ich die Log-Datei?

YANA erzeugt eine eigene Log-Datei "yana.log" im Verzeichnis "cache/". Diese Datei wird aber nur geschrieben, wenn Logging aktiviert ist. Dieses Feature ist nach der Installation per Default deaktiviert.

#### Wie aktiviere ich Logging?

Melden Sie sich als Administrator an und öffnen Sie das Administrationsmenü im Expertenmodus.

Öffnen Sie das "Programmsetup".

Aktivieren Sie die Option "Protokollierung".

Speichern Sie die Änderungen

#### Wie schreibe ich einen Eintrag in eine Log-Datei?

global $YANA
/* Einen Text in die Logs schreiben */
$log = new Log("Mein Log-Eintrag");
$YANA->report($log);
/* Text und Dump von Daten */
$dump = $irgendwelche_daten;
$log = new Log("Mein Log-Eintrag",$dump);
$YANA->report($log);
/* den erzeugten Log-Eintrag ansehen */
print $log->getLog();

#### Wie erzeuge ich eine Fehlermeldung?

##### Fehlermeldung ausgeben und Programm sofort beenden

Durch Aufruf von $YANA->message($STATE, $ERR_CODE [, $REDIRECT]) kann eine Textmeldung erzeugt werden.

DIESER BEFEHL UNTERBRICHT DIE PROGAMMAUSFÜHRUNG SOFORT UND ERZWINGT EINEN OUTPUT! Gehen sie sparsam damit um.

Der Parameter $STATE gibt den Status der Meldung an. Gültige Belegungen sind:

Wert | Beschreibung
--- | ---
OK | Erfolgsmeldung
ALERT | Hinweis
ERROR | Fehler

akzeptierte Belegungen für Parameter $STATE

Der Parameter $ERR_CODE gibt an, welche der gültigen Meldungen angezeigt werden soll. Gültige Werte für $ERR_CODE werden in den Sprachpaketen definiert. Bspw. in der Datei "language/de/message.config". Dort können auch weitere Meldungen hinzugefügt werden.

Gültige Belegungen sind unter anderem (AUSZUG):

Code | Beschreibung | Textauszug
--- | --- | ---
200 | Erfolg | Änderungen wurden gespeichert. Vielen Dank !!!
500 | Allgemeiner Fehler | Es ist ein Fehler aufgetreten...
403 | Fehler: Zugriff verweigert | Passwort erforderlich. Sie betreten einen geschützten Bereich...
UNGUELTIGE_EINGABE | Fehler: Falsche Eingabe | Ein gewählter Parameter ist ungültig...
404 | Fehler: Datei nicht gefunden | Bitte überprüfen Sie die angegebene URL und versuchen Sie es erneut.
ALLREADY_EXISTS | Fehler: Eintrag doppelt | Es konnte kein neuer Eintrag mit der id "%ID%" erzeugt werden, weil bereits ein anderes Eintrag mit diesem Namen existiert.
FILE_NOT_CREATED | Fehler: IO-Error | Die Datei "%FILE%" konnte nicht erzeugt werden.
NOT_WRITEABLE | Fehler: IO-Error | Der Schreibzugriff auf die Ressource "%FILE%" ist gescheitert. Daten konnten nicht gespeichert werden.
NOT_READABLE | Fehler: IO-Error | Der Zugriff auf die Ressource "%FILE%" ist gescheitert. Daten konnten nicht gelesen werden.

akzeptierte Belegungen für Parameter $ERR_CODE

Enthaltene Token, wie %FILE% werden ersetzt in der folgenden Weise:

$YANA->setVar('FILE', 'myFile.ext');
$YANA->message('error', 'NOT_READABLE','next_action');

##### Fehlermeldung ausgeben und Programm fortsetzen

Dies ist eine Alternative zu $YANA->message().

$YANA->report($REPORT) erzeugt ebenfalls eine Textmeldung, bricht das Programm jedoch nicht ab.

Es gibt drei Arten von Meldungen: normale Benachrichtigungen ("message"), Warnungen ("alert") und Fehler ("error"). Für jede dieser Typen gibt es jeweils eine passende Klasse: Message, Alert und Error.

Das folgende Beispiel schreibt eine Meldung in die Log-Datei und erzeugt dann einen Text für die Ausgabe am Bildschirm.

$YANA->report( new log("IO-ERROR: Unable to read file $a") );
$YANA->report( new error('NOT_READABLE', array('FILE' => $a) ) );

Vergleichen Sie den Error-Code mit der Tabelle oben.

Der Parameter $REPORT ist eine Instanz einer der folgenden Klassen:

Klasse | Beschreibung
--- | ---
log | für Ausgabe in Log-Datei
message | Erfolgsmeldung (Bildschirm)
warning | Warnung
alert | Hinweis
error | Fehler

akzeptierte Typen für Parameter $REPORT

##### Verwendung

Der Konstruktor nimmt 2 Parameter: _construct(string $text [, mixed $data]). Der Parameter $text kann ein Error-Code sein, oder auch ein beliebiger Fließtext. Für Bildschirmausgabe sollten Error-Codes verwendet werden. Für Ausgaben in die Log-Datei bietet sich englischer Fliesstext an. Der Parameter $data ist optional und enthält weitere Optionen. Beispielsweise den Datensatz, der nicht gespeichert werden konnte, oder den Namen einer Datei, die gerade nicht geöffnet werden kann.

Das besondere an $YANA->report() ist, dass Sie damit gleichzeitig Textmeldungen in die Log-Datei schreiben UND Meldungen am Bildschirm ausgeben können. Wird die Methode mehrmals aufgerufen, werden mehrere Textmeldungen am Bidlschirm ausgegeben.

    $YANA->report( new warning('FILE_NOT_CREATED', array('FILE' => $a)) );
    ...
    $YANA->report( new   alert('NOT_WRITEABLE',    array('FILE' => $a)) );
    ...
    $YANA->report( new   error('500') );
    $YANA->report( new     log("Input/Output Error in File $a", $lost_data) );
    return false;

### Profilvariablen lesen und schreiben

#### Allgemeines zum Verständnis

YANA stellt einen globalen Speicherbereich zur Verfügung, der von allen Plugins gelesen und verändert werden kann. Alle Variablen, die in diesem Bereich gespeichert werden, stehen Ihnen automatisch in allen Skins und Templates für die Ausgabe zur Verfügung. Bitte beachten Sie: der globale Speicherbereich in YANA ist etwas anderes als der global Namespace von PHP.

Innerhalb dieses Speichers werden Werte als ein Baum, in Form von mehrdimensionalen, assoziativen Arrays gespeichert. Der Zugriff auf diesen Speicherbereich erfolgt analog zu Smarty – oder, falls Ihnen der Vergleich besser gefällt, ähnlich wie mit XPath – über einen Schlüssel.

Zum Beispiel:

/* Falls der Baum so aussehen würde: */
array(
"a" => 2,
"b" => array(
"c" => 3,
1 => 4
)
);
/* Dann können Sie folgende Schlüssel verwenden: */
$array = $YANA->getVar("*"); // mit Hilfe des Schlüssels "*" erhalten Sie eine Kopie des gesamten Arrays
$int = $YANA->getVar("a"); // Ausgabe: 2
$array = $YANA->getVar("b"); // Ausgabe: array("c" => 3, 1 => 4)
$int = $YANA->getVar("b.c"); // Ausgabe: 3
/* Anders als in XML-Dateien sind hier numerische Ids erlaubt: */
$int = $YANA->getVar("b.1"); // Ausgabe: 4

#### Wie kann ich Variablen aus dem globalen Speicher lesen?

Die Funktion $YANA->getVar() erlaubt Ihnen das Lesen von Werten im globalen Speicherbereich.

global $YANA;
/* alle Werte lesen */
$array = $YANA->getVar("*");
/* einzelne Werte lesen */
$mixed = $YANA->getVar("FOO1.FOO2.FOO3");
/* alternativ */
$mixed = $YANA->registry->getVar("FOO1.FOO2.FOO3");

#### Wie kann ich Variablen im globalen Speicher schreiben?

Die Funktion $YANA->setVar() erlaubt Ihnen das Schreiben von Werten in den globalen Speicherbereich.

global $YANA;
/* Variable "MEINE_VARIABLE" registrieren */
$bool = $YANA->setVar("MEINE_VARIABLE", $neuer_wert);
$bool = $YANA->setVar("FOO1.FOO2.MEINE_VARIABLE", $neuer_wert);
/* alternativ */
$mixed = $YANA->registry->setVar("FOO1.FOO2.MEINE_VARIABLE", $neuer_wert);

#### Wie kann ich Variablen im globalen Speicher löschen?

Dazu bietet YANA die Funktion $YANA->unsetVar(). Ein Beispiel:

global $YANA;
/* Variable "MEINE_VARIABLE" löschen */
$bool = $YANA->unsetVar("MEINE_VARIABLE");
$bool = $YANA->unsetVar("FOO1.FOO2.MEINE_VARIABLE");
/* alternativ */
$mixed = $YANA->registry->unsetVar("FOO1.FOO2.MEINE_VARIABLE");

#### Wie kann ich den Typ einer Variablen im globalen Speicher ändern?

Dazu bietet YANA die Funktion $YANA->unsetVar(). Ein Beispiel:

global $YANA;
/* Variable "MEINE_VARIABLE" löschen */
$bool = $YANA->setType("MEINE_VARIABLE", "string");
$bool = $YANA->setType("FOO1.FOO2.MEINE_VARIABLE", "string");
/* alternativ */
$mixed = $YANA->registry->setType("FOO1.FOO2.MEINE_VARIABLE", "string");

#### Welche interessanten Daten liegen im globalen Speicher?

##### Liste der installierten Plugins

global $YANA;
/* eine Liste der installierten Plugins ausgeben */
$array = $YANA->getVar("INSTALLED_PLUGINS");
print_r($a);
/* Ausgabe:
Array
(
[CONFIG] => 1
[DB_ADMIN] => 1
[DEFAULT_LIBRARY] => 1
[GUESTBOOK] => 1
[GUESTBOOK_ADMIN] => 1
[USER] => 1
)
*/
/* prüfen ob ein bestimmtes Plugin installiert ist */
$bool = $YANA->getVar("INSTALLED_PLUGINS.MEIN_PLUGIN");
if ($bool) {
print "Plugin 'MEIN_PLUGIN' gefunden.";
} else {
print "Plugin 'MEIN_PLUGIN' nicht gefunden.";
}

##### aktuelle Profileinstellungen

Das "Website-Profil" wird über den URL-Parameter "id" ausgewählt. Jedes Profil kann individuelle Einstellungen haben. Diese Einstellungen werden ebenfalls im globalen Speicherbereich des Frameworks abgelegt. Wird kein Profil gewählt, dann wird das Profil "default" verwendet. De facto müssen Sie als Programmierer sich nicht darum kümmern, welches Profil gewählt ist. Sie müssen nur wissen, dass in den Profildaten Einstellungen, wie die gewählte Hintergrundfarbe der Seite, die bevorzugte Schriftart und andere interessante Daten gespeichert sind, auf die Sie bei Bedarf zugreifen können.

global $YANA;
/* die aktuellen Profileinstellungen lesen und ausgeben */
$array = $YANA->getVar("PROFILE");
print_r($array);
/* Ausgabe:

    Array
    (

    >> Layout der Website

        [BGCOLOR] => #F0F0F0
        [PFONT] => Arial, Helvetica, sans-serif
        [BGIMAGE] =>
        [LOGO] =>
        [HSIZE] =>
        [HCOLOR] =>
        [HFONT] =>
        [PSIZE] =>
        [PCOLOR] =>

    >> Gewählte Sprache, Skin und Verzeichnis für Emoticons / Smilies

        [LANGUAGE] => deutsch.config
        [SKIN] => default.config
        [SMILEYDIR] => common_files/smilies/

    >> Sonstige Einstellungen

        [USERMODE] => 1
        [AUTO] => 1
        [TIMEFORMAT] => 0

    >> Protokollierung

        [LOGGING] => 1
        [LOG_LENGTH] => 50

    >> Einstellungen für Plugin "rss to html factory"

        [RSS] => Array
            (
                [FILE] => plugins/rss/test.rss
                [MAX] => 5
            )

    >> Einstellungen für Plugin "guestbook" (Gästebuch)

        [GUESTBOOK] => Array
            (
                [NOREPLY] => noReply@meineAdresse.tld
                [FLOODING] => 0
                [ENTPERPAGE] => 5
                [NOTIFICATION] =>
                [SENDMAIL] =>
                [MAIL] => meinName@meineAdresse.tld
                [FILE] =>
                [SPAMPROTECT] => 1
                [PROFILE] =>
                [USE_DB] =>
            )

    >> Einstellungen für Plugin "search" (Stichwortsuche)

        [SEARCH] => Array
            (
                [TARGET] => _self
            )

    >> Einstellungen für Plugin "user_admin" (Nutzerverwaltung)

        [USER] => Array
            (
                [ALLOW_CREATE] => 0
            )

    )

    */

    /* die gewählte Hintergrundfarbe auslesen */
    $string = $YANA->getVar("PROFILE.BGCOLOR");
    print '<p style="background-color: '.$string.'">test</p>';

##### Default-Einstellungen

global $YANA;
/* YANA Defaut-Einstellungen ausgeben */
$array = $YANA->getVar("DEFAULT");
print_r($a);
/* Ausgabe:
Array
(
[HOMEPAGE] => sitemap
[EVENT] => Array
(
[TYPE] => default
[MODE] => 0
[PERMISSION] => 0
[TEMPLATE] => index
[INSERT] =>
)
[INTERFACE] => Array
(
[TEST] => Array
(
[TYPE] => private
[MODE] => 0
[PERMISSION] => 0
[TEMPLATE] => NULL
)
)
[SKIN] => Array
(
[DIRECTORY] => default/
)
[LANGUAGE] => Array
(
[DIRECTORY] => de/
)
[DATABASE] => Array
(
[DSN] => Array
(
[USE_ODBC] =>
[DBMS] => mysql
[HOST] => localhost
[PORT] => 0
[USERNAME] => root
[PASSWORD] =>
[DATABASE] => yana
)
[OPTIONS] => Array
(
[AUTOFREE] => 1
[PERSISTENT] => 1
[SSL] =>
)
[REQUIRE_ODBC] => Array
(
[0] => db2
[1] => access
)
)
)
*/

##### Nutzer-Informationen

global $YANA;
/* Nutzer IP */
print $YANA->getVar("REMOTE_ADDR")."\n";
/* Nutzer Name */
print $YANA->getVar("SESSION_USER_ID")."\n";
/* Zugriffslevel des Nutzers */
print $YANA->getVar("PERMISSION")."\n";
/* Session-Name */
print $YANA->getVar("SESSION_NAME")."\n";
/* Session-ID */
print $YANA->getVar("SESSION_ID")."\n";
/* Ausgabe:
127.0.0.1
ADMINISTRATOR
100
PHPSESSID
480f97e69eae2311d3157cc3377a2d73

### Verwendung eines CAPTCHA

#### Allgemeines zum Verständnis

Ein CAPTCHA ist eine Methode zum Schutz vor Spam. Dazu wird eine Grafik mit einem Text angezeigt, welchen der Besucher abtippen muss. Ein Mensch kann das mit Leichtigkeit, ein Spam-Bot hingegen kann das nicht. Auf diese Weise kann eine große Menge unerwünschter Werbung vermieden werden.

YANA hat eine Funktion zum Erzeugen einer CAPTCHA-Grafik im PNG-Format (Mime-Type „image/png“), welche einen zufällig erzeugten Code aus Zahlen und Buchstaben enthält. Ein Parameter gibt an, welche Positionsnummer dieser Code in der aktuellen Code-Tabelle hat. Die Codetabelle enthält 10 Einträge und verfällt in einem Zeitraum von 10 Minuten bis etwa 3 Stunden nach dem Aufruf der Funktion automatisch. Wenn die Tabelle abgelaufen ist, erstellt YANA automatisch eine neue Tabelle.

#### Wie benutze ich ein CAPTCHA für mein Plugin?

YANA hat eine solche Funktion bereits eingebaut. Sie müssen sich also nicht selbst darum kümmern, sondern es lediglich benutzen.

Das CAPTCHA besteht aus zwei Teilen: eine Grafik mit einem Input-Feld, welche im Template eingebunden werden müssen und einer Abfrage, welche im Quellcode des Plugins eingebunden werden muss und die true beziehungsweise false liefert, wenn die Eingabe korrekt beziehungsweise falsch war.

Dazu folgendes Beispiel:

/* Quellcode des Template */
<input type="hidden" name="security_image_index" value="[%$SECURITY_IMAGE_INDEX%]">
<img src=[%"action=security_get_image&security_image_index=$SECURITY_IMAGE_INDEX"|url%]>
<input type="text" name="security_image">
/* Quellcode des Plugins: */
global $YANA;
/* zum Erzeugen des Formulars: */
/* Die Variable "SECURITY_IMAGE_INDEX" muss für das Formular gesetzt werden.
Sie kann einen beliebigen Integerwert zwischen 1 und 9 haben. */
$YANA->setVar("SECURITY_IMAGE_INDEX", rand(1,9));
/* zum Prüfen der Eingabe: */
$bool = $YANA->handle("security_check_image", $formular_daten);
if ($bool) {
print "Eingabe korrekt.";
} else {
print "Eingabe ist falsch.";
}

### Plugins editieren

#### Wie definiere ich die Schnittstellen?

Die Schnittstelle eines Plugins wird als Datei mit der Endung "*.config" gespeichert. Sie finden diese Dateien im Verzeichnis "plugins/".

    /* in der Schnittstellenbeschreibung plugins/foo.config */

    <INTERFACE>
    	<name der aktion>

    		<TYPE>primary|default|write|read|security|config</TYPE>
    /* Type:
     - "security" für sicherheitsrelevante Funktionen, wie das Prüfen von Passwörtern
     - "config"   gedacht Funktionen zum Editieren von Konfigurationsdateien
     - "write"    für Schreibzugriffe auf dem Dateisystem oder einer Datenbank
     - "read"     für Lesezugriffe auf dem Dateisystem oder einer Datenbank
     - "default"  ist gedacht für Entwickler, die sich unschlüssig sind, wo die Aktion einzuordnen ist
    */
    		<MODE>0|1</MODE>
    /* Mode:
     - 0 (default) normaler Betriebsmodus
     - 1           Aktion im Default-Konfiguration ("abgesicherter Modus") starten
                   (für sicherheitskritische Aufgaben)
    */
    		<TEMPLATE>Id des Templates (z.Bsp. INDEX)</TEMPLATE>
    		<INSERT>Id des Templates (z.Bsp. MY_TEMPLATE)</INSERT>
    /* Templates:
     Namen von Templates für die Ausgabe
     - das unter "INSERT" angegebene Datei wird in die "TEMPLATE"-Datei eingebettet
     - "TEMPLATE" bildet also einen statischen "Rahmen" um den Inhalt, Defaultwert ist "INDEX"
     - Der Name des Templates entspricht dem Namen, der in der Skindatei festgelegt wurde.
       Zum Vergleich öffnen Sie bspw. die Datei skins/default/default.config .
     - Das spezielle Template "NULL" unterbindet dass eine Ausgabe erzeugt wird
       (sehr praktisch wenn die Ausgabe keine HTML-Datei sondern bspw. eine PNG-Grafik werden soll)
     - Das spezielle Template "MESSAGE" erzeugt eine Textmeldung.
    */

    		<PERMISSION>1</PERMISSION>
    /* Permission:
     Gibt an, welche Zugriffsrechte für einen Nutzer mindestens erforderlich sind,
     um die Aktion aufrufen zu können. Der Wert liegt zwischen 0 und 100, wobei
     der Wert 0 = "keine Beschränkung" bedeutet. Sie können eine Funktion temporär
     deaktivieren, indem Sie die Permission auf -1 setzen. In diesem Fall kann niemand
     die Aktion aufrufen.
    */
    		<ONSUCCESS>
    			<TEXT>Name der Textmeldung</TEXT>
    			<GOTO>Name der Aktion</GOTO>
    		</ONSUCCESS>
    		<ONERROR>
    			<TEXT>Name der Textmeldung</TEXT>
    			<GOTO>Name der Aktion</GOTO>
    		</ONERROR>
    /* OnSuccess / OnError:
     Sie können eine Aktion angeben, auf welche automatisch weitergeleitet werden soll,
     wenn die Aktion erfolgreich war beziehungsweise, wenn ein Fehler aufgetreten ist.

     Zusätzlich können Sie eine Textmeldung angeben, welche angezeigt werden soll.
     Eine Liste der Textmeldungen finden Sie in der Datei "languages/de/message.config".
    */
    	</name der aktion>

    /* ein Beispiel */
            <foo>
    		<TYPE>write</TYPE>
    		<MODE>0</MODE>
    		<TEMPLATE>MESSAGE</TEMPLATE>
    		<PERMISSION>75</PERMISSION>
    		<ONSUCCESS>
    			<GOTO>foo_read</GOTO>
    		</ONSUCCESS>
    		<ONERROR>
    			<GOTO>foo_edit</GOTO>
    		</ONERROR>
            <foo>
    </INTERFACE>

    /* in der Plugin-Klasse plugins/foo/plugin.php */
    class plugin_foo extends plugin
    {

    /* ... */

    	function foo($ARGS)
    	{
    		# Quelltext der Aktion "foo"
    		if ($test) {
    			return true;  # true = SUCCESS -> geht zu Aktion "foo_read"
    		} else {
    			return false; # false = ERROR  -> geht zu Aktion "foo_edit"
    		}
    	}

    	function foo_edit($ARGS)
    	{
    		# Quelltext der Aktion "foo_edit"
    	}

    	function foo_read($ARGS)
    	{
    		# Quelltext der Aktion "foo_read"
    	}

    }

#### Wie erstelle ich neue Aktionen?

Zuerst sollten Sie mit Hilfe des SDK ein Grundgerüst für Ihr neues Plugin generieren lassen. Dies macht das Anpassen des Quellcodes deutlich einfacher.

Für das Erstellen einer neuen Aktion sind zwei Dinge erforderlich. Einerseits das Schreiben des Quellcodes und andererseits die Registrierung dieser neuen Aktion im Framework selbst durch Publizieren der Schnittstelle. Dadurch wird es überhaupt erst möglich, die Aktion aufzufinden und zu benutzen.

Im Folgenden ein Beispiel: Alle öffentlichen Funktionen der Klasse stellen eine Funktion bereit, die ebenso heißt, wie die Funktion selbst. Also: um eine Aktion "foo" zu erzeugen, erstellen Sie eine Funktion "foo()". Diese rufen Sie in der URL auf über: "index.php?action=foo".

Achten Sie im Folgenden Beispiel auf die "Hot-Spots". Diese markieren Stellen im Skelett der Anwendung, welche mit eigenem Code befüllt werden können.

    class plugin_beispiel extends plugin
    {

      function plugin_beispiel($plugin_name)
      {
          settype($plugin_name,"string");
          global $YANA;

          $this->plugin_name = $plugin_name;
      }

      /**
       * Default event handler
       *
       * @param  string $event name of the called event in lower-case
       * @param  array  $ARGS  array of params passed to the function
       * @return boolean
       */
      function _default($event, $ARGS)
      {
        settype($event, "string");
        settype($ARGS, "array");

        # HOT-SPOT << hier können Sie Aktionen definieren

        # zum Beispiel mit einer Switch-Anweisung:

        switch ($event)
        {
            case 'my_action1':
                # HOT-SPOT << Code für Aktion 'my_action1'
            break;
            case 'my_action2':
                # HOT-SPOT << Code für Aktion 'my_action2'
            break;
        }

        return true;
      }

      /**
       * Type: read
       * Permission: 0
       * Templates: index entries
       *
       * @param array $ARGS array of params passed to the function
       * @return boolean
       */
      function guestbook_read_entries ($ARGS)
      {
        # HOT-SPOT << Code für Aktion 'guestbook_read_entries'
      }

    /* { ... } */

      /**
       * Type: write
       * Permission: 100
       * Templates: MESSAGE
       *
       * @param array $ARGS array of params passed to the function
       * @return boolean
       */
      function guestbook_write_write ($ARGS)
      {
        # HOT-SPOT << Code für Aktion 'guestbook_write_write'
        $YANA->message("OK", "200");
      }

      function my_action ($ARGS)
      {
        # HOT-SPOT << Code für Aktion 'my_action'
      }
    }

Die „Hot-Spots“, an welchen der Entwickler eigenen Quellcode schreiben oder ergänzen kann, sind in diesem kurzen Beispiel entsprechend hervorgehoben. Die Funktion „my_action“ soll demonstrieren, wie man nachträglich eigene Aktionen zur Schnittstelle der Klasse und damit zum Plugin hinzufügen kann. Beachten Sie die Funktion „_default“. Diese wird von der Basisklasse „plugin“ geerbt und fungiert als „Default event handler“, welcher alle Ereignisse abfängt, die an das Plugin gesendet werden, aber über die Schnittstelle der Klasse nicht implementiert sind. Außerdem fängt diese Funktion Exoten ab, wie beispielsweise Ereignisse welche ungünstigerweise ebenso benannt sind wie der Konstruktor der Klasse selbst, oder solche, welche von der Basisklasse „plugin“ geerbt wurden und somit nicht zur vom Nutzer definierten Schnittstelle der Klasse gehören können. Dies betrifft aus Sicherheitsgründen auch solche, welche in der abgeleiteten Klasse reimplementiert werden. Der Grund hierfür ist, dass diese Methoden öffentlich sind. Sie sind somit Teil einer gemeinsamen Schnittstelle aller von der Klasse „plugin“ abgeleiteten Klassen. Ihre Funktionalität wird folglich gewissermaßen durch die Implementierung der Basisklasse vorgegeben und zugesichert. Sie sollte auch in den abgeleiteten Klassen erhalten bleiben.

Um eine Funktion zu erzeugen, die nicht in der öffentlichen Schnittstelle auftauchen soll, gibt es in PHP 5 die Möglichkeit, die Funktion als "private" zu kennzeichnen. Unter PHP 4 gab es diese Option leider noch nicht. Wenn Sie PHP 4 verwenden wollen, können Sie jedoch den gleichen Effekt erreichen, indem Sie den Namend der Funktion mit einem Unterstrich "_" beginnen. Das Framework wird solche Funktionen automatisch so behandeln, als wären Sie mit "private" gekennzeichnet.

Bitte beachten: damit die neuen Funktionen verfügbar werden, müssen Sie den Plugin-Cache erneuern. Dazu loggen Sie sich als Administrator ein und klicken im Administrationsmenü auf "Liste neu laden".

### Sonstige Funktionen

#### Wie rufe ich eine Aktion eines anderen Plugins auf?

Zum Bearbeiten von Aktionen bietet YANA die Funktion $YANA->handle(), welche bei Erfolg bool(true) und sonst bool(false) zurück gibt.

global $YANA;
/* Aktion "foo" aufrufen */
$bool = $YANA->handle("foo", $parameter);
if ($bool) {
print "Die Aktion 'foo' wurde erfolgreich ausgeführt.";
} else {
print "Der Aufruf von 'foo' hat einen Fehler erzeugt.";
}

#### Wie leere ich den Template-Cache des Servers?

Dies bewirkt, dass alle Dateien mit den Endungen "*.php", "*.tmp" und "*.cache" im Verzeichnis „cache/“ des Frameworks gelöscht werden.

global $YANA;
/* Den Template-Cache des Servers leeren */
$YANA->handle("clear_server_cache", array());

#### Wie erzeuge ich, z.Bsp. in einem Forum, eine Vorschau auf den Eintrag?

/* Der folgender Eintrag im Template genügt: */
<textarea id="eingabefeld" name="text"></textarea>
<div id="vorschau"></div>
<input type="button" value="Vorschau" onclick="preview('vorschau','eingabefeld')">

© 2001, 2002, 2003, 2004, 2005, 2006Thomas Meyer, www.all-community.de/pub