TYPO3 und TypoScript Webseiten programmieren, Templates erstellen, Extensions entwickeln von Tobias Hauser, Christian Wenz, Daniel Koch 1. Auflage Hanser München 2005 Verlag C.H. Beck im Internet: www.beck.de ISBN 978 3 446 40489 2 Zu Inhaltsverzeichnis schnell und portofrei erhältlich bei beck-shop.de DIE FACHBUCHHANDLUNG
TYPO3 und TypoScript Daniel Koch Webseiten programmieren, Templates erstellen, Extensions entwickeln ISBN 3-446-40489-9 Leseprobe Weitere Informationen oder Bestellungen unter http://www.hanser.de/3-446-40489-9 sowie im Buchhandel
11.8 Weiterentwicklung der Referenzen-Extension 265 ändern oder zu löschen, den Server zu manipulieren oder Code einzuschleusen. Wie das funktioniert, soll folgendes Beispiel zeigen: $sql = "SELECT * FROM mitglied WHERE name='".$_get['name']."'"; $result = mysql_query($sql); Hierdurch wird eine typische Datenbankabfrage gestartet. Was passiert, wenn ein Angreifer den URL http://domain.tld/skript.php?name=';delete FROM mitglied WHERE 1=1 OR name=' aufruft? Dies generiert die Datenbankabfrage SELECT * FROM adressen WHERE name=''; DELETE FROM mitglied WHERE 1=1 OR name='', durch die aus der Tabelle mitglied alle Datensätze gelöscht werden. Über manipulierte SQL-Abfragen kann ein Angreifer also unter anderem Daten löschen und manipulieren. Um das zu verhindern, sollten Variablen in SQL-Abfragen immer über die Funktion mysql_real_escape_string() maskiert sein, das heißt sämtliche Sonderzeichen innerhalb von Variablen werden maskiert. So sollte kein Schaden mehr angerichtet werden. $sql = "SELECT * FROM mitglied WHERE name='".mysql_real_escape_string($_get['name'])."'"; $result = mysql_query($sql); Anders verhält es sich bei der Übergabe von numerischen Werten, was beispielsweise bei der Verwendung von IDs der Fall ist. Aber sogar hierfür gibt es eine Lösung: $sql = "SELECT * FROM adressen WHERE id=".intval($_get['id']); $result = mysql_query($sql2); Mit der Funktion inval() wird garantiert, dass es sich bei dem Wert, der in das SQL- Statement eingeführt wird, auch tatsächlich um einen numerischen Wert handelt. 11.8 Weiterentwicklung der Referenzen-Extension Im vorherigen Kapitel haben Sie eine Erweiterung programmiert, durch die Sie auf einer Seite Referenzkunden und deren jeweilige Branche anlegen können. Nun hat diese Extension jedoch einen entscheidenden Mangel: Designtechnisch ist sie ein ziemlicher Flop. In diesem Abschnitt dreht sich daher alles um die Verschönerung der Ausgabe. Im einfachsten Fall könnte man das Design mit in die PHP-Funktion integrieren. So geht allerdings die Trennung von Design, Funktion und Inhalt verloren. Es muss also ein Weg gefunden werden, über den sich Designvorlagen über PHP ansprechen und so in die Extension integrieren lassen. Als Basis dient folgende Designvorlage: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head>
266 11 Extensions <title>referenzen</title> </head> <body> <!-- ###BODY_INHALT### begin--> <table widht="50%" border="1"> <!--###REFERENZ### begin--> <tr> <td>###kunde###</td> <td>###branche###</td> </tr> <!--###REFERENZ### end--> </table> <!-- ###BODY_INHALT### end--> </body> </html> Die Datei enthält die beiden Subparts ###BODY_INHALT### und ###REFERENZEN### sowie die zwei Marker ###KUNDE### und ###BRANCHE###. In der PHP-Funktion wird davon ausgegangen, dass die Designvorlage unter referenzen.htm im Verzeichnis fileadmin/_temp_/ gespeichert ist. Die folgende bereits bekannte PHP-Funktion müssen Sie um zwei Zeilen erweitern: function main($content,$conf) { $this->conf=$conf; $this->pi_setpivardefaults(); $this->pi_loadll(); $content=""; $template = $this->cobj-> fileresource("fileadmin/_temp_/referenzen.htm"); return $template; $result = $GLOBALS["TYPO3_DB"]- >exec_selectquery("*","user_referenzen_main", "deleted = 0 AND hidden = 0", "", "", "0,2"); if (mysql_error()) debug(array(mysql_error(),$query)); while ($row = mysql_fetch_row ($result)) { echo $row[7]. " - "; echo $row[8]. "<br />"; return content; Über die TYPO3-interne Funktion fileresource() laden Sie den Inhalt der Designvorlage. Als Parameter erwartet sie den entsprechenden Pfad. Den Rückgabewert speichern Sie in der Variablen $template. Damit die folgenden Zeilen zunächst nicht weiterverarbeitet werden, verwenden Sie return $template; 3. Ein Aufruf der Seite im Frontend fördert Folgendes zu Tage: 3 Diese Zeile wird später wieder gelöscht. Hier wird sie allerdings benötigt, um die PHP-Funktion bereits jetzt testen zu können.
11.8 Weiterentwicklung der Referenzen-Extension 267 Abbildung 11.19 Die Designvorlage konnte eingebunden werden. Der hart kodierte Pfad zur Designvorlage ist zwar ein Weg, allerdings kein besonders eleganter. Besser ist es, wenn Sie den Pfad über einen Parameter übergeben. Ändern Sie dazu die $template-zeile folgendermaßen ab: $template = $this->cobj->fileresource($conf["tmpl"]); Parameter werden direkt unterhalb von plugin.user_referenzen_pi1 angesprochen. In der main()-funktion greifen Sie auf Parameter über das Array $conf[] zu. In diesem Beispiel erwartet das Array den Parameter tmpl, der natürlich noch definiert werden muss. Passen Sie dazu das Template der Seite entsprechend an: plugin.user_referenzen_pi1{ tmpl = fileadmin/_temp_/referenzen.htm Dem Parameter tmpl wird als Wert der Pfad zur Designvorlage zugewiesen. Ein erneuter Aufruf der Seite im Template liefert das gleiche Ergebnis wie zuvor. Was in diesem Beispiel der flexibleren Pfadangabe dient, lässt sich alternativ auf zahlreiche andere Wege nutzen. So können Sie beispielsweise ganze TypoScript-Objekte und deren Eigenschaften als Parameter übergeben. Wie sich das realisieren lässt, zeigt folgende Syntax: plugin.user_referenzen_pi1{ meinobjekt = IMAGE meinobjekt.file = GIFBUILDER meinobjekt.file { XY = 300,400 backcolor = #c0c0c0 10 = BOX 10.dimensions = 20,20,170,200 10.color = #808080 20 = TEXT 20.text = Hallo, Welt! 20.offset = 20,90 Das hier definierte Objekt inklusive aller Eigenschaften kann in der PHP-Funktion durch die TYPO3-interne Funktion cobjgetsingle() genutzt werden: $this->cobj->cobjgetsingle("image", $conf["meinobjekt."]); Die Funktion cobjgetsingle() erwartet zwei Parameter: Als ersten geben Sie das Objekt an, das ausgeführt werden soll. Der zweite Parameter legt die entsprechenden Objekt- Eigenschaften fest.
268 11 Extensions Das aktuelle Beispiel weist jedoch eine Besonderheit auf: Das IMAGE-Objekt wurde hier innerhalb von $conf["meinobjekt."] definiert und muss daher nicht unbedingt als IMAGE in der Funktion angegeben sein. Folgendes führt zum gleichen Ergebnis: $this->cobj->cobjgetsingle($conf["meinobjekt"], $conf["meinobjekt"]); 11.8.1 Subparts ansprechen Doch zurück zur eigentlichen Extension. Die Designvorlage ist zwar mittlerweile integriert, das reicht aber nicht. Denn weder arbeiten Sie bislang mit Subparts, noch werden die Marker durch die entsprechenden Werte aus der Datenbank ersetzt. Um mit Subparts zu arbeiten, gibt es die Funktion getsubpart(), die als Parameter die Designvorlage sowie den betreffenden Subpart erwartet. Passen Sie die PHP-Funktion folgendermaßen an: 4 $template = $this->cobj->fileresource($conf["tmpl"]); $template = $this->cobj->getsubpart($template, "###BODY_INHALT###"); Ein Blick in den Quellcode im Frontend zeigt, dass jetzt tatsächlich nur der Inhalt des Subparts ###BODY_INHALT### eingebunden ist. 11.8.2 Marker ersetzen Bislang sind die Marker nicht mit den Werten aus der Datenbank ersetzt. Damit das klappt, müssen Sie die while()-schleife der PHP-Funktion entsprechend anpassen. Zu Beginn der Funktion geben Sie ein geeignetes Array an und notieren $marker = array(); unter der bekannten $content-variablen. Anschließend lässt sich die Datenbankabfrage modifizieren: $result = $GLOBALS["TYPO3_DB"]- >exec_selectquery("*","user_referenzen_main", "deleted = 0 AND hidden = 0"); if (mysql_error()) debug(array(mysql_error(),$query)); while ($row = mysql_fetch_row ($result)) { $marker["###kunde###"] = $row[7]; $marker["###branche###"] = $row[8]; $content.=$this->cobj-> substitutemarkerarraycached($template, $marker); Die zu ersetzenden Marker werden dem Array $marker[] zugewiesen. Als Wert bekommen sie jeweils eine Spalte der Datenbank zugewiesen. Über die Funktion substitute- MarkerArrayCached() ersetzen Sie alle Marker, die innerhalb von $template (das ist der Inhalt der Designvorlage) vorkommen, durch die Werte aus der Datenbank. Der Aufruf im Frontend zeigt, dass die Marker tatsächlich ersetzt wurden. 4 Die erste Zeile ist so bereits in der Funktion vorhanden. Sie dient hier nur der Orientierung.
11.8 Weiterentwicklung der Referenzen-Extension 269 Abbildung 11.20 Die Datensätze werden ausgegeben. Einen Schönheitsfehler gibt es leider noch: Nach jedem Schleifendurchlauf wird eine neue Tabelle generiert. Um dieses Manko zu beseitigen, wurde in der Designvorlage der Subpart ##RERENZEN### eingefügt, und zwar direkt innerhalb des <table>-tags. TYPO3 muss jetzt nur dazu gebracht werden, bei jedem Datensatz ausschließlich mit diesem Subpart zu arbeiten. Realisiert wird das über die Funktion substitutesubpart(), die den Zugriff ermöglicht auf Subparts, die innerhalb eines anderen Subparts liegen. Als Parameter erwartet substitutesubpart() den Haupt-Subpart, den untergeordneten Subpart und den Inhalt, durch den der untergeordnete Subpart ersetzt werden soll. Die angepasste und jetzt vollständige main()-funktion stellt sich folgendermaßen dar: function main($content,$conf){ $this->conf=$conf; $this->pi_setpivardefaults(); $this->pi_loadll(); $content=""; $marker = array() $template = $this->cobj->fileresource($conf["tmpl"]); $template = $this->cobj->getsubpart($template, "###BODY_INHALT###"); $template_referenz = $this->cobj-> getsubpart($template, "###REFERENZ###"); $result = $GLOBALS["TYPO3_DB"]- >exec_selectquery("*","user_referenzen_main", "deleted = 0 AND hidden = 0"); if (mysql_error()) debug(array(mysql_error(),$query)); while ($row = mysql_fetch_row ($result)) { $marker["###kunde###"] = $row[7]; $marker["###branche###"] = $row[8]; $content.=$this->cobj->substitutemarkerarraycached ($template_referenz, $marker); $content = $this->cobj->substitutesubpart ($template, "###REFERENZ###", $content); return $content; Der Aufruf im Frontend liefert das gewünschte Ergebnis:
270 11 Extensions Abbildung 11.21 Jetzt ist die Ausgabe korrekt.