papaya CMS 5 Handbuch für Entwickler

Größe: px
Ab Seite anzeigen:

Download "papaya CMS 5 Handbuch für Entwickler"

Transkript

1 papaya CMS 5 Handbuch für Entwickler

2 papaya CMS 5 Handbuch für Entwickler papaya Software GmbH Kein Teil dieser Publikation darf ohne ausdrückliche schriftliche Genehmigung der papaya Software GmbH in irgendeiner Form reproduziert oder unter Verwendung elektronischer Systeme verarbeitet, vervielfältigt oder verbreitet werden. Bei der Zusammenstellung der Screenshots und Texte für dieses Dokument wurde mit größter Sorgfalt vorgegangen. Dennoch können Fehler nicht vollständig ausgeschlossen werden, da wir die Vielzahl möglicher Einflüsse durch unterschiedliche Betriebssysteme und Konfigurationen nicht überblicken können. ii

3 Inhaltsverzeichnis 1 Einleitung Für wen ist dieses Buch gedacht Aufbau des Handbuchs I Entwickeln mit papaya CMS 3 2 Wie funktioniert eigentlich papaya CMS? Die Seitenausgabe in papaya CMS Der modulare Aufbau von papaya CMS Wie sieht es unter der Haube aus? Basismodule für papaya CMS programmieren Box- und Seitenmodule programmieren POST/GET-Parameter lesen und Sessiondaten verwalten Content ausgeben und Nutzereingaben maskieren Verzeichnisse und Metadaten für Pakete erstellen Module für das Backend programmieren Eigene Anwendungen schreiben Widgets für die Benutzeroberfläche einsetzen Icons für Bearbeitungsmenü oder Adminanwendung benutzen Phrasen übersetzen Fehlersuche in papaya CMS Konfiguration der Fehlerausgabe Variablen mit base_object::debug() inspizieren Meldungen mit base_object::logmsg() protokollieren Mit base_object::addmsg() Nachrichten an Benutzer ausgeben Fehlersuche mit base_object::logvariable() Datenbankzugriffe optimieren II Referenz 157 iii

4 Inhaltsverzeichnis 6 Backend-Komponenten Übersicht über die verfügbaren Komponenten Die einzelnen Komponenten im Detail iv

5 1 Einleitung Das papaya-entwicklerhandbuch dient dazu, Ihnen als Programmierer den Einstieg in die Anwendungsentwicklung mit papaya CMS so leicht wie möglich zu machen. Sie lernen in der Einführung die technischen Konzepte von papaya CMS kennen und können tief Einblick in das System nehmen. Einzelne Tutorials ermöglichen es Ihnen sich gezielt mit den Konzepten vertraut zu machen, die Sie für die Umsetzung Ihres Projektes benötigen. Weiterführende Kapitel gehen auf Fehleranalyse und Anwendungsoptimierung ein. In der Referenz finden Sie schnell die benötigten Informationen zu Tabellen und Klassen von papaya CMS. 1.1 Für wen ist dieses Buch gedacht Dieses Buch richtet sich an Entwickler, die Erfahrung in der Programmierung webbasierter Anwendungen besitzen. Es werden grundlegende Kenntnisse in folgenden Bereichen vorausgesetzt: Objektorientierte Programmierung PHP XML XSLT SQL Bedienung von papaya CMS (siehe Benutzerhandbuch) Das Entwicklerhandbuch hat zwei Ziele: Neue Entwickler sollen schnell in das System hineinfinden, Aufbau und Funktionsweise von papaya CMS verstehen lernen, eigene Module erstellen und bestehende anpassen können. Erfahrene Entwickler sollen gezielt und direkt die Informationen nachschlagen können, die sie gerade brauchen, damit sie nicht den Quellcode durchforsten müssen. 1

6 1 Einleitung 1.2 Aufbau des Handbuchs Das Handbuch ist wie folgt aufgebaut: Kapitel 1: Einleitung enthält diese Einleitung. Teil I: Entwickeln mit papaya CMS Im ersten Teil des Handbuchs wird das System vorgestellt. Anschließend führen kleine Tutorials schrittweise in die Programmierung von papaya-modulen ein: Kapitel 2: Wie funktioniert eigentlich papaya CMS? stellt papaya CMS in seinen Grundzügen vor und beschreibt, was bei einem Seitenaufruf passiert, siehe Kapitel 2, S. 5. Kapitel 3: Basismodule für papaya CMS programmieren beschreibt, wie Sie ein Paket für papaya CMS erstellen, wie Box- und Seitenmodule programmiert werden, wie Content für die Ausgabe maskiert wird und wie Parameter und Sessiondaten von papaya CMS gehandhabt werden, siehe Kapitel 3, S. 55. Kapitel 4: Module für das Backend programmieren beschreibt, wie Sie eigene datenbankgestützte Backend-Anwendungen entwickeln können, siehe Kapitel 4, S Kapitel 5: Fehlersuche in papaya CMS stellt die in papaya CMS eingebauten Debug- Möglichkeiten vor. Sie erfahren, wie Sie PHP-Fehler protokollieren oder ausgeben können und wie Sie ihre Datenbankabfragen optimieren können, siehe Kapitel 5, S Teil II: Referenz Im zweiten Teil des Handbuchs finden Sie eine Referenz. Sie gibt Ihnen einen schnellen Überblick über das Gesamtsystem und stellt Ihnen die Datenbankstruktur vor: Kapitel 6: Backend-Komponenten stellt einige grafische Komponenten des papaya- Backends vor, siehe Kapitel 6, S

7 Teil I Entwickeln mit papaya CMS 3

8

9 2 Wie funktioniert eigentlich papaya CMS? Um papaya CMS benutzen zu können, müssen Sie keine umfangreichen technischen Kenntnisse besitzen. Jede Sekretärin, die gängige Funktionen aus Word und Excel beherrscht, lernt innerhalb weniger Stunden in einer Schulung, wie sie mit papaya CMS neue Seiten anlegen und bearbeiten kann. Wenn Sie allerdings ein bestehendes Modul erweitern oder ein neues Modul entwickeln möchten, ist es notwendig, dass Sie den Aufbau von papaya CMS verstehen. Sie müssen nachvollziehen können, wie die verwendeten Techniken zusammenwirken um Webseiten zu generieren. Die wichtigste Information ist, dass papaya CMS in der Scriptsprache PHP implementiert ist. Eine grundlegende Kenntnis dieser Sprache ist also unabdingbar, wenn Sie eigene Module erstellen möchten. Dieses Kapitel ist wie folgt aufgebaut: Wie die XML-Ausgabe eines papaya-moduls in ein Zielformat wie HTML umgewandelt wird, erfahren Sie in Abschnitt 2.1, S. 5. Näheres zum Modulkonzept von papaya CMS erfahren Sie in Abschnitt 2.2, S. 9. Was bei einem Seitenaufruf geschieht und welche Klassen und Methoden dabei genutzt werden, erfahren Sie in Abschnitt 2.3, S Die Seitenausgabe in papaya CMS Die Daten für die Seitenausgabe werden in papaya CMS durch Module aus der Datenbank ausgelesen und als XML ausgegeben. Ein Seitenmodul fungiert in diesem Fall als Schnittstelle für die Ausgabe. Die folgende Illustration stellt diesen sehr vereinfachten Vorgang vor: 5

10 2 Wie funktioniert eigentlich papaya CMS? Abbildung 2.1: Ein papaya-modul gibt XML aus In Abschnitt 2.3, S. 13 wird schrittweise und in einer weitaus höheren Detailstufe erklärt, wie eine Seite in papaya CMS aufgerufen und ausgegeben wird. Zunächst genügt es zu wissen, dass das Script vornehmlich Daten aus der Datenbank ausliest, verarbeitet und als XML ausgibt. Das folgende Listing stellt wiederum die auf das Wesentliche gekürzte XML- Ausgabe eines Seitenmoduls vor: Listing 2.1: Auszug aus der XML-Ausgabe eines Seitenmoduls 1 <page> 2 <content> 3 <topic> 4 <title>meine schönsten Bilder</title> 5 <text>hier können Sie eine Auswahl meiner schönsten Bilder bewundern.</text> 6 <image> 7 <img src="galerie.media abcdef abcdef.jpg" 8 alt="foto einer Galerie"/> 9 </image> 10 </topic> 11 </content> 12 </page> XML-Ausgabe mit Ausgabelter formatieren Die XML-Seitenausgabe ist nicht konzipiert worden, um sie direkt den Besuchern einer Website zu präsentieren. Es gibt Ausgabeformen, die dafür weitaus besser geeignet sind. Sie müssen das XML also in ein geeignetes Ausgabeformat umformen (transformieren). Meistens ist das eine Umformung nach (X)HTML, XML für einen RSS-Feed oder eine PDF- Ausgabe. Eine ausführliche Dokumentation zum Erstellen von Templates und Themes für die Ausgabe von Webseiten, RSS-Feeds und PDFs finden Sie im Handbuch papaya CMS 5: Templates und Themes erstellen. Die Technik der Wahl ist XSLT. Sie ermöglicht es, XML-Dokumente in andere Textformate umzuwandeln. Diese Aufgabe führt der XSLT-Prozessor durch. Damit der XSLT-Prozessor 6

11 2.1 Die Seitenausgabe in papaya CMS weiß, welche Vorlage (Template) er für eine bestimmte XML-Ausgabe verwenden soll, werden in papaya CMS Module (siehe Abbildung 2.1, S. 6) mit XSLT-Templates verknüpft. Diese Verknüpfung wird in papaya CMS in Form von Ansichten hergestellt. Ansichten sind Darstellungsinstanzen von Modulen. Sie verknüpfen das Modul selbst mit einem Ausgabemodus, beispielsweise HTML, RSS oder PDF. Ein Ausgabemodus entspricht dabei einem Ausgabefilter, der für ein bestimmtes Ausgabeformat wie HTML konfiguriert ist. Für den verknüpften Ausgabemodus müssen Sie anschließend eine Templatedatei auswählen, die kompatibel mit der XML-Ausgabe des Moduls ist. Der ganze Zusammenhang wird in der folgenden Grafik deutlich: Abbildung 2.2: Zusammenhang zwischen Ansichten, Ausgabemodi und Templates Im obigen Beispiel in Abbildung 2.2, S. 7 ist die Ansicht Standardseite mit den Ausgabemodi html und rss verknüpft. Für den Ausgabemodus html ist die Templatedatei page_ general.xsl, für den Ausgabemodus rss die Datei page_rss.xsl ausgewählt. Ein Modul kann beliebig viele benannte Darstellungsinstanzen in Form von Ansichten haben. Das bedeutet, dass Sie beliebig viele Ansichten mit dem selben Modul erzeugen können. Dies bietet sich vor allem dann an, wenn Sie die Ausgabe eines Moduls beispielsweise für Ihre Startseite ein wenig anders gestalten möchten. So ist im obigen Beispiel in Abbildung 2.2, S. 7 eine zweite Ansicht des Moduls Topic with image mit dem Namen Spezial angelegt, die ebenso wie die Ansicht Standardausgabe mit dem Ausgabemodus html verknüpft ist. In diesem Fall jedoch wurde das Template page_special.xsl ausgewählt. Um eine Ansicht einzusetzen, verknüpfen Sie diese mit einer Seite. Anschließend konfigurieren Sie die Seite. Das Seitenmodul stellt dazu eine entsprechende Schnittstelle zur Verfügung, über die Sie je nach Modul auch Inhalte eingeben können. Anschließend können Sie sich die Seite in der Seitenvorschau anschauen und die Seite schließlich veröffentlichen. Bei der Seitenausgabe werden die verknüpften Ausgabefilter und Templates anhand des 7

12 2 Wie funktioniert eigentlich papaya CMS? zugewiesenen Modus ausgewählt. Wird beispielsweise die Seite als index.7.html aufgerufen, erfolgt die Ausgabe der Seite in folgenden Schritten: 1. Anhand der in der URL enthaltenen Seiten-ID (in diesem Fall die 7) wird die Seite ermittelt. papaya CMS erkennt, dass die Seite mit der Ansicht Standardseite verknüpft ist. 2. Anhand der Endung html wird der angeforderte Ausgabemodus der Seite ermittelt. In der aktuellen Ansicht ist für den Modus html die Templatedatei page_general.xsl verknüpft. 3. Die XML-Ausgabe des Moduls wird erzeugt und an den Ausgabefilter übergeben. 4. Der Ausgabefilter transformiert das XML anhand der Umwandlungsregeln in der Templatedatei page_general.xsl. Das Ergebnis der Umwandlung wird als HTML-Dokument ausgegeben. Wird stattdessen index.7.rss aufgerufen, kommt page_rss.xsl zum Einsatz. In diesem Modus wird einfach ein RSS-Feed ausgegeben. Die Ausgabemodi (pdf, html, rss, print und weitere) müssen zuvor erstellt werden. Näheres dazu finden Sie im Handbuch papaya CMS 5: Handbuch für Administratoren, Kapitel 18.! Das Ansichtenkonzept ist so wesentlich für papaya CMS, dass es unbedingt nötig ist, das Prinzip verstanden zu haben. Sie vermeiden dadurch bei der Entwicklung im Dunkeln zu tappen. Nehmen Sie sich daher die Zeit, dieses Kapitel erneut zu lesen. Das Administratorhandbuch kann Ihnen weiterführende Informationen und Anleitungen bieten, mit denen Sie das Konzept an einer papaya-installation ausprobieren und nachvollziehen können. HTML-Ausgabe mit CSS-Denitionen und Schmuckgraken formatieren Nun ist schlichtes HTML nicht sonderlich ansprechend. Da Sie sicherlich darauf bedacht sind, Inhalt und Darstellung voneinander zu trennen, und es guter moderner Entwicklungsstil ist, werden CSS-Definitionen nicht direkt in die HTML-Ausgabe geschrieben, sondern CSS-Dateien (Stylesheets) verwendet. Im Zusammenhang mit papaya CMS wird eine Sammlung von CSS-Dateien und Layout-Bildern, die einer Webseite Stil geben, meistens als Theme bezeichnet. Im Unterschied zu diesen Theme-Bildern, die der Dekoration dienen, werden Inhaltsbilder vom System verwaltet, näheres dazu finden Sie im Handbuch papaya CMS 5: Handbuch für Administratoren, Kapitel 5. 8

13 2.2 Der modulare Aufbau von papaya CMS Abbildung 2.3: HTML + CSS = schöne Webseite Sie haben gesehen: Seitenmodule von papaya CMS geben XML aus. Ein Seitenmodul ist zudem über eine Ansicht mit einem Ausgabefilter und einem XSLT-Template verknüpft. Der Ausgabefilter wandelt die XML-Ausgabe des Moduls in ein Zielformat wie HTML um und nutzt dabei die Transformationsregeln aus dem XSLT-Template. Eine Ansicht kann dabei beliebig viele Zielformate über Ausgabemodi zugewiesen bekommen. 2.2 Der modulare Aufbau von papaya CMS Das Modulkonzept in papaya CMS In papaya CMS sind Funktionen an vielen Stellen als Modul gekapselt. Das hat viele Vorteile. So lassen sich eigene Module erstellen, die anstelle der standardmäßig vorhandenen zum Einsatz kommen. Dadurch kann das Verhalten des Systems in der Tiefe beeinflusst werden, ohne dass es inkompatibel für Aktualisierungen wird. Des weiteren kann ein Modul komplett neu geschrieben werden, wenn es die Umstände erfordern. Lediglich die Methoden müssen gleich bleiben, die darin aufgerufen werden. Module werden in Paketen verwaltet. Ein Paket ist zunächst einmal nichts anderes als ein Verzeichnis, in dem sich die PHP-Dateien befinden. Jedes Paket besitzt zudem eine XML- Datei, modules.xml, in der alle Module des Pakets im Detail beschrieben sind. Näheres zur Struktur der modules.xml können Sie in Abschnitt 3.4.3, S. 91 erfahren Modultypen in papaya CMS Die folgende Tabelle enthält eine Übersicht aller Modultypen von papaya CMS: 9

14 10 Tabelle 2.1: Modultypen Modultyp Identifier Dateinamenspräfix Beschreibung Seiten page content_ Seiten sind das Fundament, auf denen alle Ausgaben basieren. Boxen box actbox_ Häufig wiederkehrende Inhalte, die auf unterschiedlichen Seiten auftreten, werden als Boxen umgesetzt. Cronjobs cronjob cronjob_ Mit Cronjobs lassen sich regelmäßige Aufgaben durchführen, die nicht an Seitenaufrufe gekoppelt sein sollen oder dürfen. Zeiten time time_ Zeitmodule dienen der Berechnung von Zeitintervallen oder eines bestimmten Zeitpunktes in Form eines Datums. Sie werden sowohl im Calendar-Paket als auch von Cronjob-Modulen genutzt. Statistic statistic statistic_ Statistikmodule (kommerziell) geben Einblick in die Nutzung einer Website und helfen, sie zu optimieren. Importfilter import import_ Über Importfilter lassen sich theoretisch beliebige Daten in papaya CMS importieren. 2 Wie funktioniert eigentlich papaya CMS?

15 11 Tabelle 2.1: Modultypen (forts.) Modultyp Identifier Dateinamenspräfix Beschreibung Ausgabefilter output output_ Die Ausgabe der Module wird meistens über XSLT weiterverarbeitet oder über einen Ausgabefilter, der PDF erstellt. Datenfilter datafilter datafilter_ Datenfilter können verwendet werden um Inhalte vor der Ausgabe nochmals zu verändern. Beispielsweise können mit dem Glossar-Paket (kommerziell) Fachwörter in Artikeln mit Einträgen aus dem Glossar verlinkt werden. Administration admin edmodule_ admin_ Die meisten Pakete von papaya CMS bringen eine eigene Administrationsoberfläche mit, über die Module konfiguriert werden können und Inhalte überwacht oder erstellt werden. Bil- dynamische der image image_ Dank GD können Buttons, Fortschrittsbalken und Ranking als Grafiken dynamisch generiert werden. 2.2 Der modulare Aufbau von papaya CMS

16 12 Tabelle 2.1: Modultypen (forts.) Modultyp Identifier Dateinamenspräfix Beschreibung Aliase alias alias_ Aliase sind URLs, die auf eine andere URL verweisen. Meistens, damit die URL schöner aussieht oder sich besser merken lässt. Durch Module kann die Funktionsweise von Aliasen umfangreich angepasst werden. Konnektoren connector connector_ Wenn unterschiedliche Module miteinander interagieren sollen, muss man eine klare Schnittstelle definieren. Das geschieht über so genannte Konnektoren. Parser parser parser_ Ein Parser-Modul ermöglicht es eigene XML-Tags zu verwenden, die von dem Modul entsprechend ausgewertet werden. Über den Richtext-Editor können diese Inhalte bequem eingefügt werden. 2 Wie funktioniert eigentlich papaya CMS?

17 2.3 Wie sieht es unter der Haube aus? Im normalen Arbeitsalltag kommen vorwiegend Content-, Box- und Adminmodule zum Einsatz. Bei großen Projekten mit verschiedenen Paketen spielen auch Konnektoren und Cronjobs eine größere Rolle Klassenstruktur von Modulen Die Klassenhierarchie von Modulen sieht wie folgt aus: Abbildung 2.4: Klassenhierarchie von Modulen Das bedeutet, alle Module sind von base_object und base_plugin abgeleitet und je nach Modultyp noch von einer weiteren Elternklasse. Damit stehen uns zum einen die Methoden der Elternklassen zur Verfügung, zum anderen müssen ein paar der Methoden, die dort nur als Interface angegeben sind, im eigenen Modul implementiert werden. Welche Methoden für welche Modultypen das sind, erfahren Sie in Kapitel 3, S Wie sieht es unter der Haube aus? Dieses Kapitel beschreibt im Detail, wie ein Seitenaufruf durch den Webserver und papaya CMS verarbeitet wird. An einem Seitenrequest wird beispielhaft erklärt, wie die Seitenanfrage erst durch den Webserver verarbeitet und anschließend an papaya CMS weitergereicht wird. Die beteiligten papaya-klassen und ihre Methoden werden in der Reihenfolge ihrer Aufrufe beschrieben. 13

18 2 Wie funktioniert eigentlich papaya CMS?! Wenn Sie die detaillierten Hintergrundinformationen in diesem Abschnitt nicht benötigen und Sie direkt in die Programmierung von Content- oder Box-Modulen einsteigen möchten, können Sie in Kapitel 3, S. 55 weiterlesen. Die einzelnen aufgerufenen Instanzen sind folgende: 1. Webserver mit.htaccess-datei, siehe Abschnitt 2.3.1, S Aufruf von papaya CMS über die index.php, siehe Abschnitt 2.3.2, S Konfigurationsdatei conf.inc.php laden, siehe Abschnitt 2.3.3, S Seiten- und Dateiausgabe durch papaya_page.php kontrollieren, siehe Abschnitt 2.3.4, S Konfigurationsoptionen aus der Datenbank laden (base_options.php), siehe Abschnitt 2.3.5, S Seiten-Content für Preview-Modus (papaya_topic.php) und Frontend (papaya_ topic_public.php) ausgeben, siehe Abschnitt 2.3.6, S Webserver verarbeitet.htaccess-regeln papaya CMS wird mit einer standardisierten.htaccess-datei ausgeliefert. Wenn eine Seitenanfrage an den Webserver geht, interpretiert der Webserver (vorausgesetzt, es ist Apache) zuerst die.htaccess-datei. Diese Datei enthält Regeln und Konfigurationsoptionen, die den aktuellen Seitenaufruf beeinflussen. Die.htaccess-Datei aus der papaya-standarddistribution enthält hauptsächlich Rewrite-Regeln, mit denen die URLs umgeschrieben werden. In einer weiteren Option wird ein statisches HTML-Dokument definiert, das eine generische 404-Fehlermeldung darstellt. Weitere Optionen steuern die Ausgabe des Expires-Headers. Das URL-Rewriting wird aus folgenden Gründen verwendet: Mit dem Rewriting von URLs lassen sich suchmaschinenfreundliche Links erzeugen, da bestimmte Informationen wie die Seiten-ID, die Sprachversion oder die ID der Kategorie nicht über URL-Parameter an die index.html übergeben werden. Statische Dateien und Verzeichnisse haben Vorrang vor virtuellen. Dieser Umstand wird durch entsprechende Rewrite-Regeln durchgesetzt, wobei statische Dateien (mit Ausnahme der Dateien in der MediaDB) direkt durch Apache ausgeliefert werden, ohne dass papaya CMS diese Aufgabe übernehmen müsste. Dies bringt einige Performance- Vorteile mit sich. 14

19 2.3 Wie sieht es unter der Haube aus? Wenn im Browser des Nutzers Cookies deaktiviert sind, wird die Session-ID in der Regel als GET-Parameter an die URL gehängt. Damit die URLs aber immer noch leserlich bleiben, wird die Session-ID durch Rewriting in den Pfad der URL geschrieben. Dadurch geht die Session-ID nicht so leicht verloren und sie kann nicht so einfach geändert werden. Für eine erste Übersicht ist die vollständige.htaccess-datei im folgenden Listing dargestellt: 1 RewriteEngine On 2 Listing 2.2:.htaccess-Datei aus papaya CMS (Revision 20064) 3 #remove session id 4 RewriteRule ^/?sid[a-z]*([a-za-z0-9,-]{20,40})(/.*) $2 [QSA] 5 6 #admin pages 7 RewriteCond %{REQUEST_FILENAME}!-d 8 RewriteCond %{REQUEST_FILENAME}!-f 9 RewriteRule ^/?papaya/module\_([a-z\d\_]+)\.[a-z]{3,4} /papaya/module.php?p_module=$1 [QSA,L] #media files - public / static 12 RewriteRule ^/?[^./]*\.(thumb media)\.((.).*) - [E=mediaFile:/papaya-files/$3/$2] 13 RewriteCond %{DOCUMENT_ROOT}%{ENV:mediaFile} -f 14 RewriteRule ^/?[^./]*\.(thumb media)\.((.).*) /papaya-files/$3/$2 [L] #media files - wrapper script 17 #RewriteCond %{REQUEST_FILENAME}!-f 18 RewriteRule ^/?([a-fa-f0-9]/)*[a-za-z0-9_-]+\.(media thumb download popup image)(\.(preview))?((\.([a-za-z0-9_]+))?(\.[a-za-z0-9_]+)) /index.php [QSA,L] #output pages 21 RewriteCond %{REQUEST_FILENAME}!-d 22 RewriteCond %{REQUEST_FILENAME}!-f 23 RewriteRule ^/?[a-za-z0-9_-]+((\.[0-9]+)?\.[0-9]+)((\.[a-z]{2,5})?\.[a-z]+)((\.[0-9]+)?. preview)? /index.php [QSA,L] 24 RewriteCond %{REQUEST_FILENAME}!-d 25 RewriteCond %{REQUEST_FILENAME}!-f 26 RewriteRule ^/?index((\.[a-z]{2,5})?\.[a-z]+)((\.[0-9]+)?.preview)? /index.php [QSA,L] ErrorDocument 404 /index.php #optimize cache headers for static content (if possible) 31 FileETag none 32 <IfModule mod_expires.c> 33 ExpiresActive on 34 ExpiresDefault A </IfModule> 36 <IfModule mod_headers.c> 37 <FilesMatch "\.(ico pdf flv jpg jpeg png gif js css swf)$"> 38 Header set Cache-Control "public, max-age= , pre-check= " 39 </FilesMatch> 40 </IfModule> 15

20 2 Wie funktioniert eigentlich papaya CMS?! Weitere Informationen zu.htaccess-dateienaufbau und Funktionsweise von.htaccess-dateien sind ausführlich im Apache-Handbuch unter beschrieben. Die Dokumentation zu dem Modul mod_rewrite finden Sie unter folgender URL: Weitere Informationen zur.htaccess-datei in papaya CMSDie Standard-.htaccess von papaya CMS ist auf die Installation im DocumentRoot einer Domain ausgelegt. Wenn papaya CMS in einem Unterverzeichnis installiert werden soll, muss die htaccess.tpl aus dem readme-verzeichnis angepasst und ins DocumentRoot kopiert werden - nicht in das verwendete Unterverzeichnis. Die.htaccess muss also trotz Installation im Unterverzeichnis im DocumentRoot der Domain liegen. Wenn für die Domain schon eine Konfiguration in der.htaccess besteht, müssen diese zusammengeführt werden. Näheres dazu können Sie im Handbuch papaya CMS 5: Handbuch für Administratoren, Abschnitt erfahren. Die Apache-Direktiven in der.htaccess-datei Mit der ersten Anweisung wird das Apachemodul mod_rewrite aktiviert. Andernfalls können keine Regeln definiert werden: 1 RewriteEngine On Listing 2.3: Rewrite-Engine aktivieren Wird die Session über die URL weitergegeben, entfernt die folgende Rewrite-Regel die Session-ID aus dem Query-String. Die Session-ID wird in der Regel an den Query-String gehängt, wenn Cookies deaktiviert sind, siehe dazu die Option PAPAYA_SESSION_ID_FALLBACK. Die Session ID wird entfernt, indem alles an den Ziel-Querystring angehängt wird, was nicht sid[a-z]* ist (QSA, query string append): Listing 2.4: Session-ID aus dem Query-String entfernen 1 #remove session id 2 RewriteRule ^/?sid[a-z]*([a-za-z0-9,-]{20,40})(/.*) $2 [QSA] Die folgenden Rewrite-Bedingungen gelten für Requests aus dem Admin-Bereich: Listing 2.5: Requests für den Admin-Bereich umschreiben 1 #admin pages 2 RewriteCond %{REQUEST_FILENAME}!-d 3 RewriteCond %{REQUEST_FILENAME}!-f 4 RewriteRule ^/?papaya/module\_([a-z\d\_]+)\.[a-z]{3,4} /papaya/module.php?p_module=$1 [QSA,L] 16

21 2.3 Wie sieht es unter der Haube aus? Zunächst wird überprüft, ob die angeforderte Ressource nicht eine existierende Datei (!- f) oder ein Verzeichnis (!-d) ist. Physisch vorhandene Dateien und Verzeichnisse werden vorrangig ausgegeben, da sie verfügbar sein sollen. Wenn weder eine Datei noch ein Verzeichnis an dieser Stelle existiert, kann die nachfolgende Regel angewendet werden. Diese besagt, dass alle Aufrufe von /papaya/module_<modulname>.ext umgeschrieben werden in /papaya/module.php?p_module=<modulname>, wiederum angehängt an den Query-String (QSA). Wenn diese Regel trifft, werden alle weiteren Regeln ignoriert (L = last, letzte). Die folgende Bedingung prüft, ob statische Mediadaten vorhanden sind. Ist das der Fall, werden diese ausgeliefert und das Rewriting abgeschlossen: Listing 2.6: Statische Mediadateien direkt ausliefern 1 #media files - public / static 2 RewriteRule ^/?[^./]*\.(thumb media)\.((.).*) - [E=mediaFile:/papaya-files/$3/$2] 3 RewriteCond %{DOCUMENT_ROOT}%{ENV:mediaFile} -f 4 RewriteRule ^/?[^./]*\.(thumb media)\.((.).*) /papaya-files/$3/$2 [L] Wenn ein Aufruf direkt Inhalte der MediadDB anfordert, wird dieser an index.php weitergeleitet. Der Query-String wird an die index.php angehängt und der Redirect beendet (L). URLs für MediaDB-Inhalte haben in der Regen die Struktur [filename].[ identifier].[filehash].[extension], was in der Rewrite-Regel durch einen regulären Ausdruck kodiert ist: Listing 2.7: MediaDB-Aufrufe an die index.php weiterleiten 1 #media files - wrapper script 2 RewriteRule ^/?([a-fa-f0-9]/)*[a-za-z0-9_-]+\.(media thumb download popup image)(\.(preview))?((\.([a-za-z0-9_]+))?(\.[a-za-z0-9_]+)) /index.php [QSA,L] Bei ganz normalen Seiten kommen diese zwei Regelsätze zum tragen. Es wird jeweils wieder sichergestellt, dass keine Datei oder ein Verzeichnis mit dem angegebenen Namen tatsächlich existiert (!-d,!-f), denn diese werden vorrangig behandelt: Listing 2.8: URL-Umformung bei Seitenausgabe im Frontend 1 #output pages 2 RewriteCond %{REQUEST_FILENAME}!-d 3 RewriteCond %{REQUEST_FILENAME}!-f 4 RewriteRule ^/?[a-za-z0-9_-]+((\.[0-9]+)?\.[0-9]+)((\.[a-z]{2,5})?\.[a-z]+)((\.[0-9]+)?. preview)? /index.php [QSA,L] 5 RewriteCond %{REQUEST_FILENAME}!-d 6 RewriteCond %{REQUEST_FILENAME}!-f 7 RewriteRule ^/?index((\.[a-z]{2,5})?\.[a-z]+)((\.[0-9]+)?.preview)? /index.php [QSA,L] Die Regeln sind wieder als reguläre Ausdrücke kodiert. Die erste Regel trifft bei allen Aufrufen einer Ausgabeseite der folgenden Form: Listing 2.9: Erste Rewrite-Regel für folgende URL-Formen 1 filename.topicid.lngid.extension 2 filename.categoryid.topicid.lngid.extension.versiontime.preview 17

22 2 Wie funktioniert eigentlich papaya CMS? Die zweite Regel trifft bei URLs, die folgende Form aufweisen: Listing 2.10: Zweite Rewrite-Regel für folgende URL-Formen 1 index.lngid.extension.versiontime.preview In beiden Fällen wird der Querystring angehängt (QSA) und der Redirect beendet (L). Die Bedeutung der einzelnen Felder ist in der folgenden Tabelle aufgeschlüsselt: Feldname filename categoryid topicid lngid extension versiontime preview Tabelle 2.2: Bestandteile einer URL (Frontend) in papaya CMS Bedeutung Entspricht dem Dateinamensteil der angeforderten Ressource. Optional: Eine numerische ID, die beispielsweise in der Kataloganwendung einer Katalog-ID entspricht. Numerische ID, die der Seiten-ID entspricht. Wenn diese ID weggelassen wird, stellt papaya CMS automatisch die Standardseite dar. Zwei- bis fünfstellige Buchstabenfolge, die die Content- Sprache kodiert. Auch diese Angabe ist optional. Wenn die lngid weggelassen wird, liefert papaya CMS die Standardsprachversion der Seite aus. Dateiendung, welche das Ausgabeformat der Seite bestimmt. Eine gültige Dateiendung wird bei der Konfiguration des Ausgabefilters definiert. Standardmäßig wird die Endung html für Webseiten angegeben. Optional kann ein UNIX-Timestamp angehängt werden. Dadurch wird die zu dieser angegebenen Zeit veröffentlichte Seitenversion dargestellt. Wenn Sie diese Endung an die URL hängen, sehen Sie die Vorschau der noch unveröffentlichten Seite. Diese Ansicht ist nur dann zugänglich, wenn Sie gleichzeitig im Backend von papaya CMS angemeldet sind. Diese Zeile weist Apache an, beim HTTP-Statuscode 404 (Datei nicht gefunden), die index. php aufzurufen, damit sich papaya CMS um den Fehler kümmern kann: 1 ErrorDocument 404 /index.php Listing 2.11: Fehlerbehandlung an papaya CMS delegieren 18

23 2.3 Wie sieht es unter der Haube aus? Diese Direktive weist Apache an, keinen ETag für Dateien zu vergeben: Listing 2.12: FileETag-Ausgabe durch Apache deaktivieren 1 #optimize cache headers for static content (if possible) 2 FileETag none Es gibt zwei Gründe, warum die ETag-Ausgabe durch Apache deaktiviert wird: papaya CMS übernimmt selbst die Ausgabe von ETags. Standardmäßig benutzt Apache für die ETag-Berechnung die Inode-Nummer der Dateien, was beim Einsatz von gespiegelten Servern hinter einem Load-Balancer zu falschen Ergebnissen führt, da die Inode-Nummern der gleichen angeforderten Datei auf verschiedenen Servern unterschiedlich sind.! Was ist ein ETag?Die Abkürzung ETag steht für Entity Tag und bezeichnet ein Header- Feld aus dem HTTP-Standard der Version 1.1 ( siehe RFC 2616). Mit diesem Header- Feld kann ein Server angeben, nach welcher Zeit eine angeforderte Ressource aktualisiert wird. Dadurch können Browser erkennen, ob die Ressource im Browsercache vorgehalten werden kann. Durch das Cachen entfällt das wiederholte und damit redundante Herunterladen von ein und der selben Ressource. Falls das Apache-Modul mod_expires verfügbar ist, wird die Ausgabe der Expires- und Cache-Control-Header zunächst einmal aktiviert. Mit dem an ExpiresDefault übergebenen Wert wird angegeben, dass das angeforderte Dokument Sekunden (entspricht 30 Tagen) nach dem letzten Zugriff durch den Client (Code A ) neu geladen werden kann, da der Cache nach Ablauf dieser Zeit ungültig wird. Davon unberührt bleiben Expires-Header, die von papaya CMS für verschiedene Dateien speziell gesetzt werden: 1 <IfModule mod_expires.c> 2 ExpiresActive on 3 ExpiresDefault A </IfModule> Listing 2.13: Apache-Modul mod_expires aktivieren Wenn das Apache-Modul mod_headers verfügbar ist, wird ein Cache-Control-Header für alle Dateien vom Typ ico, PDF, flv, jpg, png, gif, js, css sowie swf gesetzt: Listing 2.14: Cache-Control-Header setzen 1 <IfModule mod_headers.c> 2 <FilesMatch "\.(ico pdf flv jpg jpeg png gif js css swf)$"> 3 Header set Cache-Control "public, max-age= , pre-check= " 4 </FilesMatch> 5 </IfModule> 19

24 2 Wie funktioniert eigentlich papaya CMS? Die Cache-Zeit wird dabei jeweils auf Sekunden (30 Tage) gesetzt (max-age). Mit public wird darüber hinaus angegeben, dass die angeforderte Ressource durch alle Zwischenstationen im Cache vorgehalten werden darf. pre-check definiert einen Update- Intervall in Sekunden, in dem der Client eine Ressource aktualisieren muss. Eine Ressource wird dabei erst nach dem Update angezeigt, sodass der Nutzer im Client den Updatevorgang ggf. in Form eines Nachladens beobachten kann Aufruf von papaya CMS über index.php Wenn Apache keine lokale Datei ausliefert, werden alle Anfragen an die index.php von papaya CMS weitergegeben. Die index.php ist das Hauptscript, das vom Webserver angesprochen wird, sobald eine Seite oder Datei ausgegeben werden soll. Das Script befindet sich im Installationsverzeichnis von papaya CMS, beispielsweise im DocumentRoot. Die index.php bindet zunächst die Datei conf.inc.php ein. Diese Datei enthält die Basiskonfiguration der Webseite. Zur Basiskonfiguration gehören die Zugangsdaten zur Datenbank und grundlegende Konfigurationsoptionen (siehe Abschnitt 2.3.3, S. 22). Zu Beginn der index.php wird bestimmt, wie Fehlermeldungen ausgegeben werden: Listing 2.15: Bestimmung des Errorhandlings 1 if (defined( PAPAYA_DBG_DEVMODE ) && PAPAYA_DBG_DEVMODE) { 2 $PAPAYA_FOUND_LIBRARY = include_once(papaya_include_path. system/papaya_page.php ); 3 } else { 4 $PAPAYA_FOUND_LIBRARY system/papaya_page.php ); 5 } Wenn der Entwicklermodus (PAPAYA_DBG_DEVMODE) aktiv ist, wird keine Fehlerunterdrückung beim Einbinden der papaya_page.php verwendet. Die Klasse papaya_page ist für die Seiten- und Dateiauslieferung zuständig. Bei aktivierter Fehlerausgabe werden bei nicht vorhandenen Dateien oder Seiten umfangreiche Fehlerbehandlungen und Weiterleitungen durchgeführt. Mehr dazu erfahren Sie in Abschnitt 2.3.4, S. 22. Falls das Basissystem von papaya CMS nicht gefunden wurde oder der Wartungsmodus (maintenance) aktiviert ist, wird ein entsprechender Status-Code (503) ausgegeben. Dafür wird zunächst getestet, ob PHP im CGI-Modus betrieben wird. Ist dies der Fall, sendet die index.php einen Status-Header, ansonsten einen HTTP-Header. Der HTTP-Fehlercode ist 503 und besagt, dass der Dienst zurzeit nicht verfügbar ist: Listing 2.16: 503-Fehlermeldung bei falscher Konfiguration 1 if ((!$PAPAYA_FOUND_LIBRARY) (defined( PAPAYA_MAINTENANCE_MODE ) && PAPAYA_MAINTENANCE_MODE)) { 2 if (php_sapi_name() == cgi php_sapi_name() == fast-cgi ) { Status: 503 Service Unavailable ); 4 } else { 20

25 2.3 Wie sieht es unter der Haube aus? HTTP/ Service Unavailable ); 6 } Im folgenden Schritt wird geprüft, ob der Wartungsmodus aktiviert worden ist: Listing 2.17: Überprüfung des Wartungsmodus 1 if (defined( PAPAYA_MAINTENANCE_MODE ) && PAPAYA_MAINTENANCE_MODE && 2 defined( PAPAYA_ERRORDOCUMENT_MAINTENANCE ) && file_exists( PAPAYA_ERRORDOCUMENT_MAINTENANCE) && 3 is_file(papaya_errordocument_maintenance) && is_readable(papaya_errordocument_maintenance )) { 4 header( Content-type: text/html; charset=utf-8; ); 5 readfile(papaya_errordocument_maintenance); 6 } elseif (defined( PAPAYA_ERRORDOCUMENT_503 ) && file_exists(papaya_errordocument_503) && 7 is_file(papaya_errordocument_503) && is_readable(papaya_errordocument_503)) { 8 header( Content-type: text/html; charset=utf-8; ); 9 readfile(papaya_errordocument_503); 10 } else { 11 echo Service Unavailable ; 12 } Ist der Wartungsmodus aktiviert und wurde eine existierende Datei als Fehlerdokument definiert, wird diese ausgeliefert. Alternativ wird das 503-Fehlerdokument ausgegeben, sofern es vorhanden ist. Wenn alle Stricke reißen, wird alternativ der Text Service unavailable ausgegeben. Wenn das Basissystem gefunden werden konnte und der Wartungsmodus nicht aktiviert worden ist, wird versucht, die Revisionsdatei revision.inc.php einzubinden: Listing 2.18: Revsisionsdatei revision.inc.php einbinden 1 } else { 2 if ((!defined( PAPAYA_WEBSITE_REVISION )) && is_readable( revision.inc.php )) { 3 require_once(./revision.inc.php ); 4 } 5 $PAPAYA_PAGE = &new papaya_page(); 6 $PAPAYA_PAGE->execute(); 7 $PAPAYA_PAGE->get(); 8 } Die Revisionsdatei gibt Auskunft über den Versionsstand einer papaya-installation. Im letzten Block wird eine Instanz von papaya_page erstellt. Zunächst wird die Methode papaya_ page::execute() aufgerufen, anschließend die Methode papaya_page::get(). Die letzte Methode erzeugt die Ausgabe für die aufgerufene URL. Im folgenden Abschnitt wird die Konfigurationsdatei conf.inc.php besprochen. 21

26 2 Wie funktioniert eigentlich papaya CMS? Kongurationsdatei conf.inc.php laden Die Datei conf.inc.php enthält die grundlegende Konfiguration für eine papaya-installation. Sie befindet sich im selben Verzeichnis wie die Datei index.php. Außer Konstantendefinitionen und Kommentaren sollte diese Datei nichts enthalten. Die conf.inc. php enthält alle Optionen, die nicht über das Backend einstellbar sind. Zusätzlich können für Entwicklungs- oder Demoserver Optionen definiert werden, die nicht verändert oder überladen werden sollen. papaya CMS prüft, ob eine Konstante existiert, bevor es diese mit dem Wert aus der Tabelle papaya_options oder dem Standardwert füllt. Die Kommentare erklären die meisten Optionen ausreichend. Näheres zu den Optionen erfahren Sie in papaya CMS 5: Handbuch für Administratoren, Abschnitt Seiten- und Dateiausgabe durch papaya_page kontrollieren Die Klasse papaya_page ist maßgeblich verantwortlich für die Seiten- und Dateienausgabe im Frontend. Außerdem werden in der Klasse papaya_page Fehlerkonstanten definiert. Anhand der Fehlernummern der entsprechenden Konstanten lässt sich leichter herausfinden, wodurch ein Problem verursacht wurde. Der Fehlercode erscheint hinter dem HTTP-Fehlercode. Im folgenden Screenshot wird die Ausgabe einer Fehlermeldung (hier die 303) dargestellt: Abbildung 2.5: Beispiel für eine Fehlerausgabe mit papaya-spezifischem Fehlercode 22

27 2.3 Wie sieht es unter der Haube aus? Im oben dargestellten Fall ist für den Ausgabemodus html kein Verzeichnis relativ zum eingestellten PAPAYA_LAYOUT_TEMPLATES angegeben. Dies wird mit dem Fehlercode 303 quittiert. Funktion execute() ausführen Nachdem in der index.php eine Instanz der Klasse papaya_page erzeugt worden ist, wird die Funktion execute() der Instanz aufgerufen. Die Funktion execute() ruft als erstes papaya_page::starttimer() auf. Dadurch wird der Zeitpunkt festgehalten, zu dem die Seitenausgabe gestartet wird. Anschließend werden einige Konstanten und Klassenattribute gesetzt. Normalerweise enthält $_SERVER[ HTTP_HOST ] den Host-Header des Requests. Wenn der Client keinen Host-Header mitgeschickt hat, ist $_SERVER[ HTTP_HOST ] leer. Als Fallback wird der Wert von $_SERVER[ SERVER_NAME ] verwendet, um die Variable nutzen zu können. $_SERVER[ SERVER_NAME ] enthält den Servernamen oder VirtualHost, in dessen Umgebung papaya CMS läuft. Dann wird das Domainhandling initialisiert und ausgeführt. Zu diesem Zweck wird die Klasse base_domains eingesetzt. Diese Klasse ermöglicht es mit einer papaya-installation unterschiedliche Domains mit abweichenden Inhalten zu bedienen: Listing 2.19: Domainverwaltung einbinden 1 include_once(papaya_include_path. system/base_domains.php ); 2 $this->domains = &new base_domains(); 3 $this->domains->handledomain(); papaya_page::loadoptions() instanziiert die Klasse base_options und führt base_ options::loadanddefine() aus. Sollte dies fehlschlagen, wird der anschließende Abschnitt zur Fehlerbehandlung ausgeführt. Es wird der 503-Header, Service unavailable, gesendet und versucht das Fehlerdokument zu lesen. Ist das Fehlerdokument vorhanden und lesbar, wird es ausgegeben, andernfalls wird die Standardfehlerausgabe von papaya CMS verwendet: Listing 2.20: Systemoptionen aus der Datenbank laden 1 $this->domains = &new base_domains(); 2 $this->domains->handledomain(); 3 if (!$this->loadoptions()) { 4 $this->sendhttpstatus(503); 5 if (defined( PAPAYA_ERRORDOCUMENT_503 ) && 6 file_exists(papaya_errordocument_503) && 7 is_file(papaya_errordocument_503) && 8 is_readable(papaya_errordocument_503)) { 9 $this->sendheader( Content-type: text/html; charset=utf-8; ); 10 readfile(papaya_errordocument_503); 11 } else { 12 $this->geterrorhtml(503, Service Unavailable, PAPAYA_PAGE_ERROR_DATABASE); 23

28 2 Wie funktioniert eigentlich papaya CMS? 13 } 14 exit; 15 } papaya_page::geterror() verwendet einen Redirect um Fehler anzuzeigen. Wenn ein Access denied (403), File not found (404) oder ein nicht näher bezeichneter Internal Server Error (500) auftritt, wird papaya_page::geterror() aufgerufen: Listing 2.21: Fehlermeldungen ausgeben 1 if (isset($_get[ redirect ]) && $_GET[ redirect ] && 2 in_array($_get[ redirect ], array(403, 404, 500))) { 3 $message = empty($_get[ msg ])? : $_GET[ msg ]; 4 $code = empty($_get[ code ])? 0 : $_GET[ code ]; 5 $this->geterror($_get[ redirect ], $message, $code); 6 exit; 7 } Im folgenden Schritt wird mit base_object::parserequesturi() das Array $_SERVER[ REQUEST_URI ] zerlegt. Die Ergebnisse werden in $this->requestdata gespeichert. $_SERVER[ REQUEST_URI ] enthält den Pfad auf dem Server ohne den Domainnamen. Dabei werden alle von papaya CMS benötigten Informationen wie Seiten-ID, Sprache usw. aus dem Pfad extrahiert: Listing 2.22: Request-URI parsen und in Bestandteile zerlegen 1 $this->requestdata = base_object::parserequesturi(); Diese extrahierten Informationen werden in der Methode papaya_page::initializeparams( ) verarbeitet. papaya_page::initializeparams() Die Instanzmethode initializeparams() wird aufgerufen: 1 $this->initializeparams(); Listing 2.23: Parameter initialisieren Ziel dieser Methode ist es, die zu verwendende Seiten-ID zu ermitteln. Sie kümmert sich auch um eine eventuell vorhandene Box-ID. Dazu werden die Parameter $_REQUEST[ tt ][ page_id ] und $_REQUEST[ p_id ] herangezogen: Listing 2.24: $this->initializeparams: Topic-ID bestimmen 1 function initializeparams() { 2 if (isset($_request[ tt ][ page_id ]) && $_REQUEST[ tt ][ page_id ] > 0) { 3 $this->topicid = (int)$_request[ tt ][ page_id ]; 4 } elseif (isset($_request[ p_id ]) && $_REQUEST[ p_id ] > 0) { 24

29 2.3 Wie sieht es unter der Haube aus? 5 $this->topicid = (int)$_request[ p_id ]; 6 } elseif (isset($this->requestdata[ page_id ]) && 7 $this->requestdata[ page_id ] > 0) { 8 $this->topicid = (int)$this->requestdata[ page_id ]; 9 $_REQUEST[ p_id ] = (int)$this->requestdata[ page_id ]; Der Wert des Parameter $_REQUEST[ tt ][ page_id ] wird dabei in der Instanzvariable $this->topicid gespeichert. Falls $_REQUEST[ tt ][ page_id ] nicht gesetzt ist, wird stattdessen $_REQUEST[ p_id ] herangezogen. Mit papaya_page::checkalias() wird überprüft, ob es sich bei der URL um einen Alias handelt, also um eine Kurz-URL, die auf eine papaya-seite verweist. Wird eine Aliasseite ermittelt, wird sie als aktuelle Seiten-ID gesetzt: Listing 2.25: $this->initializeparams: Aliasseite bestimmen 10 } else { 11 $aliaspage = $this->checkalias(); 12 if (TRUE === $aliaspage) { 13 $this->topicid = -1; 14 } elseif (FALSE === $aliaspage) { 15 $this->topicid = (int)papaya_pageid_default; 16 } else { 17 $this->topicid = (int)$aliaspage; 18 } Um diesen Block besser zu verstehen, wird im folgenden Abschnitt die Funktion checkalias() erläutert. Die Methode papaya_page::checkalias() Die Methode papaya_page::checkalias() überprüft, ob für die angegebene URL ein Alias definiert ist. Die Aliasüberprüfung findet nur statt, wenn der Redirect-Status 404 (File not found) lautet, andernfalls ist die Datei oder der Ordner physisch vorhanden und soll auch verwendet werden. Eine 404-Statusmeldung kann in diesem Zusammenhang in folgenden Fällen auftreten: CSS-Hack für den IE-Mac Fehlende Datei favicon.ico Diese Fälle müssen speziell behandelt werden. Es kommt vor, dass der CSS-Hack für den IE-Mac von Browsern so interpretiert wird, das Requests der Form oder */ entstehen. Damit diese nicht zu 404-Fehlern führen, werden sie von papaya_page:: checkalias() mit dem Code 200 (OK) quittiert und beendet. 25

30 2 Wie funktioniert eigentlich papaya CMS? Im folgenden Schritt werden 404-Redirects überprüft. Wenn also in der REQUEST_URI der Dateiname favicon.ico auftaucht, wird versucht, anstelle der fehlenden Datei im DocumentRoot ein favicon.ico im Theme-Pfad zu finden. Falls die Datei gefunden werden konnte, wird sie mit papaya_file_delivery ausgeliefert. Näheres dazu im Abschnitt papaya_file_delivery. Das Script wird anschließend zur Sicherheit beendet; in papaya_file_delivery sollte allerdings bereits ein exit ausgeführt worden sein. Wurde kein favicon gefunden, wird ein 404-Fehler generiert und das Script beendet: Listing 2.26: checkalias() - Handling von 404-Fehlern 1 if (isset($_server[ REDIRECT_STATUS ]) && $_SERVER[ REDIRECT_STATUS ] == 404) { 2 $requesturi = isset($_server[ REQUEST_URI ])? $_SERVER[ REQUEST_URI ] : ; 3 if (preg_match( (^/?([\\("] \\\\")), $requesturi)) { 4 /* mac-ie css hack handling - path starts with ( or " */ 5 $this->sendhttpstatus(200); 6 exit; 7 } elseif (preg_match( (^/?blank.gif), $requesturi)) { 8 //Handling of relative location headers emitted by ivw box } elseif (preg_match( (favicon\.ico)i, $requesturi)) { 11 /* if we get an error for a favicon.ico - let s look in the theme */ 12 $webfile = papaya-themes/.papaya_layout_theme. /favicon.ico ; 13 $localfile = $this->getbasepath(true).$webfile; 14 if (file_exists($localfile) && is_readable($localfile)) { 15 $filedata = array( 16 file_name => favicon.ico, 17 file_size => filesize($localfile), 18 mimetype => image/x-icon 19 ); 20 $this->sendhttpstatus(200); 21 include_once(papaya_include_path. system/papaya_file_delivery.php ); 22 papaya_file_delivery::outputfile($localfile, $filedata); 23 exit; 24 } else { 25 $this->geterror( , 27 File/path.$_SERVER[ REDIRECT_URL ]. not found, 28 PAPAYA_PAGE_ERROR_PATH 29 ); 30 } 31 exit; 32 } Wenn weder ein CSS-Hack für den Mac-IE abgefangen noch ein favicon.ico gesucht werden muss, können echte Aliase behandeln werden. Dazu wird die Klasse base_urlmounter instanziiert und die Methode base_urlmounter::locate() aufgerufen. Die Methode base_urlmounter::locate() versucht aus der REQUEST_URI einen existierenden Alias abzulesen und die entsprechende papaya-seite zu finden. Näheres dazu im Abschnitt base_urlmounter. $alias ist ein Array, dessen zweiter Wert den Redirect-Modus enthält (0 = Weiterleitung, 1 = Frameset, 2 = Modul). Je nach Redirect-Modus wird nun unterschiedlich vorgegangen: Listing 2.27: Weiterleitung über Aliasmodul 1 include_once(papaya_include_path. system/base_urlmounter.php ); 2 $urlmounter = &new base_urlmounter; 3 if ($alias = $urlmounter->locate()) { 4 switch ($alias[1]) { 26

31 2.3 Wie sieht es unter der Haube aus? 5 case 2 : 6 if ($url = $urlmounter->executealiasplugin($alias[2])) { 7 if (is_string($url)) { 8 if ($alquiasurl = $urlmounter->getaliasurl($url)) { 9 $this->sendhttpstatus(302); 10 $this->sendheader( X-Papaya-Status: alias plugin redirect ); 11 $this->sendheader( Location:.$aliasURL); 12 exit(); Wenn der Redirect-Modus 2 ist, wird ein Aliasmodul ausgeführt, das eine URL zurückliefern soll. Wenn die Ressource gefunden wird, die in der URL spezifiziert ist, sendet papaya CMS den Redirect-Header 302 (Moved Permanently) und leitet an die Seite weiter. Wenn es sich nicht um ein Aliasmodul, sondern um einen einfachen Alias handelt, gibt die Funktion checkalias() die ID der papaya-seite zurück, auf die der Alias verweist: Listing 2.28: Weiterleitung über Alias-Seite 1 } else { 2 define( PAPAYA_ALIAS_PAGE, TRUE); 3 //parse url and set request data 4 include_once(papaya_include_path. system/base_url_analyze.php ); 5 $requestdata = base_url_analyze::parseurl($url); 6 $this->requestdata = $this->parserequesturi($requestdata[ path ]); 7 $this->mode = $this->requestdata[ ext ]; 8 if (!empty($_server[ REDIRECT_QUERY_STRING ])) { 9 $_GET = $this->querystringtoarray($_server[ REDIRECT_QUERY_STRING ]); 10 } 11 if (!empty($requestdata[ query ])) { 12 $_GET = array_merge_recursive( 13 $_GET, 14 $this->querystringtoarray($requestdata[ query ]) 15 ); 16 } 17 return $this->requestdata[ page_id ]; 18 } 19 } elseif (is_array($url)) { 20 return $this->setrequestfromalias($url); 21 } elseif ($url === TRUE) { 22 //url was handled in plugin 23 exit; 24 } 25 } 26 break; Zurück zur Methode papaya_page::initializeparams() Im letzten Schritt wird $_REQUEST[ p_id ] mit der ermittelten ID überschrieben, die im Attribut $this->topicid gespeichert worden ist: Listing 2.29: Feld $_REQUEST[ p_id] mit $this->topicid überschreiben 19 $_REQUEST[ p_id ] = $this->topicid; 20 } 27

32 2 Wie funktioniert eigentlich papaya CMS? Die Information in $_REQUEST[ p_id ] wird in papaya_rpc benötigt. Wenn aus der URI eine Sprachangabe (language) ermittelt werden konnte, wird diese in $ _REQUEST[ language ] gespeichert. base_object::getweblink() verwendet diese Information. Listing 2.30: $this->initializeparams: Sprachcode ermitteln 21 if (isset($this->requestdata[ language ])) { 22 $_REQUEST[ language ] = $this->requestdata[ language ]; 23 } Im Attribut $this->boxid wird die ID der Box gespeichert, für die eine Seitenvorschau erzeugt werden soll. Für die Vorschau von Boxen wird immer eine Seite benötigt, die im Attribut $this->topicid angegeben ist: Listing 2.31: $this->initializeparams: Box-ID ermitteln 24 if (isset($_get[ papaya_box_preview ]) && $_GET[ papaya_box_preview ] > 0) { 25 $this->boxid = (int)$_get[ papaya_box_preview ]; 26 } else { 27 $this->boxid = -1; 28 } 29 } Damit ist die Methode initializeparams() zu Ende. Im folgenden Abschnitt wird die Methode initpagemode() besprochen. Diese Methode bestimmt unter anderem den Ausgabemodus der Seite. papaya_page::initpagemode() In papaya_page::execute() wird im folgenden Schritt die Instanzmethode $this->initpagemode( ) aufgerufen: 1 $this->initpagemode(); Listing 2.32: $this->initpagemode() aufrufen Mit der Methode papaya_page::initpagemode() wird die Seitenversion und der Ausgabemodus ermittelt. Außerdem wird festgestellt, ob die Session gestartet werden soll und wenn ja, ob sie schreibbar sein soll. Zunächst wird die Seitenversion bestimmt. Dazu werden die Parameter $_GET[ p_date ] sowie der Requestparameter datetime ausgewertet, der in der URL enthalten sein kann: Listing 2.33: Seitenversion bestimmen 28

33 2.3 Wie sieht es unter der Haube aus? 1 function initpagemode() { 2 $this->versiondatetime = 0; 3 if (isset($_get[ p_date ])) { 4 $this->versiondatetime = (int)$_get[ p_date ]; 5 } elseif (isset($this->requestdata[ datetime ]) && 6 $this->requestdata[ datetime ] > 0) { 7 $this->versiondatetime = (int)$this->requestdata[ datetime ]; 8 } Im Vorschaumodus wird der Status der Seite auf nicht öffentlich ($this->public = FALSE) gesetzt. Andernfalls wird, wenn der Parameter public übergeben wird, der Status dann öffentlich, wenn dieser yes enthält. Ist der Parameter nicht gesetzt, wird die Versionszeit auf 0 gesetzt und der Status auf öffentlich ($this->public = TRUE): Listing 2.34: Vorschaumodus bestimmen 1 if (isset($this->requestdata[ preview ]) && $this->requestdata[ preview ]) { 2 $this->public = FALSE; 3 } elseif (isset($_get[ public ])) { 4 $this->public = ($_GET[ public ] == yes ); 5 } else { 6 $this->versiondatetime = 0; 7 $this->public = TRUE; 8 }! In base_object::parserequesturi() wird durch den regulären Ausdruck sichergestellt, dass es keine Versionszeit im öffentlichen Modus gibt. Anschließend muss der Ausgabemodus bestimmt werden. Wenn die in der URL enthaltene Erweiterung xml ist, wird $_GET[ XML ] auf 1 gesetzt. Dieser Eintrag wird später durch das Layoutobjekt (eine Instanz der Klasse papaya_xsl) ausgewertet, siehe Abschnitt 2.3.6, S. 48. Der Modus wird schließlich auf xml gesetzt. Ist php die Erweiterung, wird der konfigurierte Standardmodus verwendet, als Fallback html. Andernfalls wird der Modus anhand der Dateiendung gesetzt: Listing 2.35: Ausgabemodus bestimmen 1 switch ($this->requestdata[ ext ]) { 2 case xml : 3 $_GET[ XML ] = 1; 4 $this->mode = xml ; 5 break; 6 case php : 7 $this->mode = defined( PAPAYA_URL_EXTENSION )? 8 PAPAYA_URL_EXTENSION : html ; 9 break; 10 default: 11 $this->mode = $this->requestdata[ ext ]; 12 } Als nächstes wird papaya_output benötigt. Diese Klasse initialisierte den Ausgabefilter: 29

34 2 Wie funktioniert eigentlich papaya CMS? Listing 2.36: Ausgabefilter initialisieren 1 include_once(papaya_include_path. system/papaya_output.php ); 2 unset($this->output); 3 $this->output = &new papaya_output; Wenn der aktuelle Ausgabemodus in der Liste $pagemodes enthalten ist, darf eine Session gestartet werden. Allerdings ist nur der lesende Zugriff erlaubt, da diese Ausgaben keine Änderungen benötigen: Listing 2.37: Read-Only-Session starten 1 $pagemodes = array( urls, status, thumb, media, popup, download ); 2 if (isset($this->mode) && in_array($this->mode, $pagemodes)) { 3 $this->readonlysession = TRUE; 4 $this->allowsession = TRUE; Die Session nur lesend zu starten verkürzt die Scriptlaufzeit. Kommt ein anderer Ausgabemodus zum Tragen, wird das Ausgabemodul angewiesen die Ansichtsdaten für den Modus zu laden. Je nach Konfiguration des Ausgabefilters wird eine Session gestartet oder nicht und entschieden, ob sie schreibbar ist oder nicht (1 = Nur lesen, 2 = Keine Session, 0 = Standard): Listing 2.38: Konfiguration des Ausgabefilters laden 1 } elseif ($this->output->loadviewmodedata($this->mode)) { 2 switch ($this->output->viewmode[ viewmode_sessionmode ]) { 3 case 1 : 4 //read only session 5 $this->allowsession = TRUE; 6 $this->readonlysession = TRUE; 7 break; 8 case 2 : 9 //no session 10 $this->allowsession = FALSE; 11 $this->readonlysession = TRUE; 12 break; 13 case 0 : 14 default : 15 //default handling 16 $this->allowsession = TRUE; 17 $this->readonlysession = FALSE; 18 break; 19 } Die Session-Einstellung wird beim Ausgabefilter für jede Erweiterung eingestellt. Wurde kein passender Modus für die Ansicht gefunden, wird eine änderbare Session erlaubt: 1 } else { 2 $this->allowsession = TRUE; 3 $this->readonlysession = FALSE; Listing 2.39: Standard-Session-Einstellungen ausgeben 30

35 2.3 Wie sieht es unter der Haube aus? 4 } 5 } Damit endet die Methode papaya_page::initpagemode(). papaya_page::startsession() Im folgenden Schritt wird in papaya_page::execute() die Instanzmethode startsession( ) ausgeführt: 1 $this->startsession(); Listing 2.40: Instanzmethode startsession() ausführen Wenn per Konfiguration eine Session für jeden Besucher gestartet werden soll, initialisiert papaya_page::startsession() diese: Listing 2.41: Sessionstart-Flag setzen 1 function startsession() { 2 if (!(isset($this->sessionobj) && is_object($this->sessionobj))) { 3 if (!$this->public) { 4 $startsession = TRUE; 5 } elseif ($this->allowsession && PAPAYA_START_SESSION) { 6 $startsession = TRUE; 7 } else { 8 $startsession = FALSE; 9 } Wenn eine nicht-öffentliche Seite aufgerufen wird, muss der Benutzer angemeldet sein; es wird auf jeden Fall eine Session benötigt. Wenn papaya_page::initpagemode() ergeben hat, dass der Ausgabemodus eine Session benötigt und die Konfiguration Sessions erlaubt, wird auch eine Session gestartet, andernfalls nicht. Wenn ein Fallback für die Session konfiguriert wurde, wird dieses verwendet. Ansonsten wird rewrite verwendet. Falls die Seite nicht öffentlich ist und der Fallbackmodus rewrite oder get ist, wird der Fallbackmodus auch auf rewrite gesetzt: Listing 2.42: Fallback-Modus für Session-IDs setzen 10 $fallback = defined( PAPAYA_SESSION_ID_FALLBACK )? 11 PAPAYA_SESSION_ID_FALLBACK : rewrite ; 12 if (!($this->public && ($fallback == rewrite $fallback == get ))) { 13 $fallback = rewrite ; 14 } Wenn eine Session gestartet werden und die Datenbankverbindung nicht persistent sein soll, wird diese geschlossen. Dadurch wird die DB-Verbindung nicht belegt, während die Session erstellt wird: 31

36 2 Wie funktioniert eigentlich papaya CMS? Listing 2.43: Nicht-persistente Datenbankverbindung schließen 15 if ($startsession && 16!(defined( PAPAYA_DB_CONNECT_PERSISTENT ) && PAPAYA_DB_CONNECT_PERSISTENT)) { 17 $this->output->databaseclose(); 18 } Nun wird das Sessionobjekt instanziiert und die Session gestartet (falls erwünscht): Listing 2.44: Sessionobjekt instanziieren 19 include_once(papaya_include_path. system/sys_session.php ); 20 $this->sessionobj = &rewrite_session::getinstance( 21 $this->sessionname, 22 $startsession, 23 $fallback); Wenn die Session nur gelesen werden muss, wird sie direkt geschlossen. Damit sind die Sessionparameter nur noch lesbar. 24 if ($this->readonlysession) { 25 $this->sessionobj->close(); 26 } Listing 2.45: Read-Only-Session direkt schließen Dann werden die Sessionparameter der Seite geladen: Listing 2.46: Session-Parameter der Seite laden 27 $this->sessionparams = $this->sessionobj->getvalue( PAPAYA_SESSION_PAGE_PARAMS ); Zuletzt wird noch das Surferobjekt instanziiert. Damit werden später u.a. Zugriffsrechte überprüft: Listing 2.47: Surfer-Objekt instanziiert 28 include_once(papaya_include_path. system/base_surfer.php ); 29 $this->surferobj = &base_surfer::getinstance(); 30 } Damit wird die Methode papaya_page::startsession() beendet. Exit-Seiten bearbeiten! Was ist eine Exit-Seite?Eine Exit-Seite ist eine Webseite, die ein Nutzer aufruft und damit das von papaya CMS verwaltete Webangebot verlässt. Solche Seiten werden im Idealfall als GET-Parameter mit dem Namen exit für die Webnutzungsstatistik erfasst. Als Parameter-Wert wird eine URL erwartet, auf die papaya CMS weiterleitet. Die URL ist entweder ein absoluter Webpfad oder eine vollständige Adresse mit Protokoll, Domainname und Webpfad. 32

37 2.3 Wie sieht es unter der Haube aus? Wenn eine Exitseite per $_GET[ exit ] angegeben wurde, wird die Weiterleitung angestoßen: Listing 2.48: Auf Exit-Seiten weiterleiten 1 if (isset($_get[ exit ])) { 2 if (preg_match( #^/sid.preg_quote($this->sessionname). 3 ([a-za-z\d,-]{20,40})([^?]*)#i, 4 $_SERVER[ REQUEST_URI ], $regs)) { 5 $protocol = (isset($_server[ HTTPS ]) && $_SERVER[ HTTPS ] == on )? 6 https : http ; 7 $url = $protocol. ://.strtolower(papaya_default_host).$regs[2]. 8?exit=.urlencode($_GET[ exit ]); 9 $this->sendhttpstatus(301); 10 $this->sendheader( X-Papaya-Status: external link ); 11 $this->sendheader( Location:.$url); Wenn eine Session-ID in der aktuellen URL vorhanden ist, wird diese entfernt und eine Weiterleitung angestoßen. Der HTTP-Status 301 besagt, dass die URL mit der Session-ID nicht korrekt ist und die gültige URL für diesen Link die nachfolgende URL ist (die ohne Session- ID). Wenn keine Session mehr in der URL zu finden ist, wird die Ziel-URL als Exit-Seite für die Statistik geloggt: Listing 2.49: Ziel-URL als Exit-Seite für die Statistik protokollieren 1 } else { 2 $targeturl = $_GET[ exit ]; 3 $this->logrequestexitpage($targeturl); 4 } 5 exit; 6 } Dazu wird die Session geschlossen und überprüft, ob überhaupt Statistikdaten geschrieben werden sollen. Wenn ja, wird das Statistikobjekt base_statistic_logging initialisiert, der Request und die Exitpage geloggt. Da anschließend das Script beendet wird, kann das normale Loggen der Statistik bei Seitenaufrufen nicht erfolgen. papaya_page::protectedredirect(): Geschützte Weiterleitung auf externe URLs Anschließend wird zur Zielseite weitergeleitet, wieder mit dem HTTP-Status 301 (Moved Permanently): Listing 2.50: Geschützte Weiterleitung auf externe Seite 1 $this->protectedredirect(301, $targeturl); 33

38 2 Wie funktioniert eigentlich papaya CMS? Dabei wird sichergestellt, dass keine externen oder unerlaubten Seiten eine papaya-installation nutzen, um URLs harmlos aussehen zu lassen. Der Methodenaufruf benötigt den HTTP-Status, der übermittelt werden soll, und eine Ziel-URL: Listing 2.51: papaya_page::protectedredirect() aufrufen 1 function protectedredirect($code, $targeturl) { 2 if (!defined( PAPAYA_REDIRECT_PROTECTION ) PAPAYA_REDIRECT_PROTECTION) { 3 $protocol = (isset($_server[ HTTPS ]) && $_SERVER[ HTTPS ] == on )? 4 https : http ; 5 $systemurl = $protocol. ://.strtolower(papaya_default_host); Wenn die Redirect-Protection nicht explizit ausgeschaltet wurde, wird zunächst das Protokoll sowie die System-URL ermittelt. Wenn die Ziel-URL die System-URL enthält, ist die Domain identisch und die Weiterleitung wird erlaubt: Listing 2.52: Domains von Ziel- und System-URL vergleichen 6 if (0 === strpos($targeturl, $systemurl)) { 7 //own hostname - just redirect 8 $this->sendhttpstatus($status); 9 $this->sendheader( X-Papaya-Status: absolute link ); 10 $this->sendheader( Location:.$targetURL);ie Wenn der Referrer die eigene Domain beinhaltet, kommt der Aufruf von der eigenen Domain, die Weiterleitung wird erlaubt: Listing 2.53: Weiterleitung bei eigener Domain 11 } elseif (isset($_server[ HTTP_REFERER ]) && 12 0 === strpos($_server[ HTTP_REFERER ], $systemurl)) { 13 //from own hostname - just redirect 14 $this->sendhttpstatus($status); 15 $this->sendheader( X-Papaya-Status: external link (referer checked) ); 16 $this->sendheader( Location:.$targetURL); Wenn die obigen Fälle nicht zutreffen, wird die Ziel-URL geprüft. Dazu wird in der Domainverwaltung geschaut, ob die Ziel-Domain in der Liste enthalten ist: Listing 2.54: Ziel-URL in der Domainverwaltung überprüfen 17 } else { 18 include_once(papaya_include_path. system/base_url_analyze.php ); 19 $urldata = base_url_analyze::parseurl($targeturl); 20 if ($this->domains->load($urldata[ host ], 0)) { 21 $this->sendhttpstatus($status); 22 $this->sendheader( X-Papaya-Status: external link (domain checked) ); 23 $this->sendheader( Location:.$targetURL); 24 } else { 25 $this->getredirect($code, $targeturl); 26 } 27 } 34

39 2.3 Wie sieht es unter der Haube aus? In dem Fall wird sie als bekannt akzeptiert und weitergeleitet. Wenn nicht, wird die Methode getredirect() ausgeführt. Die genaue Funktionsweise dieser Methode ist in der Klassenreferenz von papaya_page erklärt. Auf einer speziellen papaya-seite wird dem Benutzer anzeigt, dass er im Begriff ist die Webseite zu verlassen. Über einen Link kann er diese Seite erreichen, falls er das wirklich möchte. Wenn keine spezielle Seite vorhanden ist, wird eine einfache HTML-Standardausgabe angezeigt. Wenn die Sicherheitsprüfung abgeschaltet ist, wird einfach auf die Zielseite weitergeleitet: Listing 2.55: Weiterleitung bei deaktivierter Sicherheitsüberprüfung 28 } else { 29 //protection disabled 30 $this->sendhttpstatus($status); 31 $this->sendheader( X-Papaya-Status: redirect link ); 32 $this->sendheader( Location:.$targetURL); 33 } 34 exit; 35 } Die Methode papaya_page::protectedredirect() beendet das Script. Zurück in die Methode papaya_page::execute(). Das Exit-Handling wird durch ein exit abgeschlossen. Das Script wird damit beendet, es gibt nichts mehr zu tun. Der Browser leitet den Benutzer auf die Zielseite weiter. papaya_page::execute(): Redirect-Request verarbeiten Wenn der Parameter $_REQUEST[ redirect ] gesetzt ist, wird die absolute Ziel-URL ermittelt und erneut ein abgesicherter Redirect durchgeführt (Details s.o.): Listing 2.56: Redirect-Request verarbeiten 1 /* redirect script handling */ 2 if (isset($_request[ redirect ])) { 3 $targeturl = base_object::getabsoluteurl($_request[ redirect title ]); 4 $this->protectedredirect(302, $targeturl); 5 exit; 6 } In diesem Fall wird der HTTP-Status 302, Found, übermittelt. Mit diesem Status-Code wird dem Client mitgeteilt, dass die aktuelle URL weiterhin gültig ist. Das Script wird beendet. Wenn Sie einen Default-Host eingerichtet haben und die Default-Action redirect (>0) ist, wird der Status 301 (moved permanently) übermittelt und mit dem aktuellen Protokoll auf die URL im Default-Host weitergeleitet: 35

40 2 Wie funktioniert eigentlich papaya CMS? Listing 2.57: Weiterleitung auf Standard-Host 1 if (defined( PAPAYA_DEFAULT_HOST ) && trim(papaya_default_host)!= && 2 defined( PAPAYA_DEFAULT_HOST_ACTION ) && PAPAYA_DEFAULT_HOST_ACTION > 0 && 3 strtolower($_server[ HTTP_HOST ])!= strtolower(papaya_default_host)) { 4 $this->sendhttpstatus(301); 5 $protocol = (isset($_server[ HTTPS ]) && $_SERVER[ HTTPS ] == on )? 6 https : http ; 7 $url = $_SERVER[ REQUEST_URI ]; 8 $this->sendheader( X-Papaya-Status: redirecting to default host ); 9 $this->sendheader( Location:.$protocol. ://.strtolower(papaya_default_host).$url); 10 exit; 11 } Das Error-Reporting wird auf den Wert gesetzt, den Sie in der Konfiguration angegeben haben: 1 if (defined( PAPAYA_DBG_PHP_ERROR )) { 2 error_reporting(papaya_dbg_php_error); 3 } Listing 2.58: Werte für Error-Reporting setzen Anschließend wird das Logging-Objekt initialisiert, wenn PAPAYA_GLOBAL_LOGOBJECT gesetzt ist, was in base_options erfolgt: Listing 2.59: Globales Logging-Objekt initialisieren 1 if (defined( PAPAYA_GLOBAL_LOGOBJECT ) && (trim(papaya_global_logobject)!= )) { 2 include_once(papaya_include_path. system/base_log.php ); 3 $GLOBALS[PAPAYA_GLOBAL_LOGOBJECT] = &new base_log(); 4 } Nun wird noch überprüft, ob Gzip verwendet werden kann: 1 $this->checkacceptgzip(); Listing 2.60: GZip-Unterstützung überprüfen Diese Funktion überprüft folgende Eigenschaften: Die Funktion gzopen() existiert, d.h. die Funktionalität ist in PHP vorhanden. Die Ausgabekompression ist in der Systemkonfiguration aktiviert worden. Die Cache-Vorhaltezeit ist größer als 0. Komprimieren hat nur Sinn, wenn das Ergebnis auch zwischengespeichert und später weiterverwendet werden kann. Die Server-Variable $_SERVER[ HTTP_ACCEPT_ENCODING ] muss gzip enthalten, d.h. der Client muss mit Inhalten, die mit gzip komprimiert worden sind, etwas anfangen können. Die Methode papaya_page::execute() ist damit beendet. Der nächste und letzte Aufruf in der index.php ist die Methode papaya_page::get(). 36

41 2.3 Wie sieht es unter der Haube aus? Die Methode papaya_page::get() Anhand des in papaya_page::initpagemode() ermittelten Modus wird in der Methode papaya_page::get() entschieden, was für eine Art Ausgabe erfolgt. Im Switch- Case-Block werden anschließend entsprechede Methoden aufgerufen: Listing 2.61: papaya_page::get() 1 function get() { 2 $this->sendheader( X-Generator: papaya CMS ); 3 switch ($this->mode) { 4 case urls : 5 $this->geturls(); 6 break; 7 case status : 8 $this->getstatus(); 9 break; 10 case image : 11 $this->getdynamicimage(); 12 break; 13 case thumb : 14 $this->getmediathumbfile(); 15 break; 16 case media : 17 $this->getmediafile(); 18 break; 19 case popup : 20 $this->getmediapopup(); 21 break; 22 case download : 23 $this->outputdownload(); 24 break; 25 case outputs : 26 $this->getoutputs(); 27 break; 28 case xml : 29 $this->getxmloutput(); 30 break; 31 default: 32 return $this->getpageoutput(); 33 } 34 } Die folgende Tabelle schlüsselt die Bedeutung der jeweiligen Modi im Switch-Case-Block auf: Modus urls status image Tabelle 2.3: Mögliche Werte für $this->mode mit Erklärung der Ausgabe Erklärung Ausgabe aller veröffentlichten Seiten als simple Linkliste für Suchmaschinen Verbindungsstatus der Datenbank, die die Information enthält, ob die Verbindung verfügbar ist oder nicht. Ausgabe eines dynamisch generierten Bildes, z.b. für Captchas. 37

42 2 Wie funktioniert eigentlich papaya CMS? Tabelle 2.3: Mögliche Werte für $this->mode mit Erklärung der Ausgabe (forts.) Modus thumb media popup download outputs xml default -Fall Erklärung Ausgabe eines skalierten Bildes. Ausgabe eines Bildes oder einer anderen Media-Datei. Ausgabe eines Bildes in einem Popup-Fenster. Ausgabe einer Media-Datei als Download. Liste aller möglichen Ausgabeversionen der aktuellen Seite. XML-Ausgabe der Seite, die vom XSLT-Template transformiert wird. Die Seite wird im angegebenen Ausgabemodus gerendert. Ob dieser vorhanden ist, wird später geprüft. Damit ist auch das Script index.php beendet. Im folgenden Abschnitt wird die Methode papaya_page::sendheader() ausführlich beschrieben. Diese Methode wird in der Klasse papaya_page sehr oft benutzt, um HTTP- Header auszugeben. Sie ist also von sehr zentraler Bedeutung. Die Methode papaya_page::sendheader() Die Methode papaya_page::sendheader() ist ein Wrapper für die PHP-Funktion header( ). Wurden bereits Header ausgegeben (passiert, wenn das erste Mal Text ausgegeben wird), wird beim ersten folgenden Aufruf von sendheader() ein Eintrag in das Protokoll geschrieben. Auf einem Produktivsystem sollte niemals der Fall eintreten, dass Header gesendet werden, nachdem die Ausgabe erfolgt ist. Meistens passiert dies auf dem Entwicklungssystem, wenn eine Fehlermeldung ausgegeben wird. Zum Thema Konfiguration der Fehlerausgabe und der Debugeinstellungen bitte im Handbuch für Administratoren nachschlagen. Zunächst werden die Variablen $headersent, $file und $line initialisiert. Die lokale Variable $headersent ist static, damit es bei jedem Aufruf der Methode in einem Scriptdurchlauf den Wert behält. $file und $line werden von headers_sent() gefüllt: Listing 2.62: Methodensignatur und lokale Variablen von sendheader() 1 function sendheader($headerstr) { 2 static $headerssent; 38

43 2.3 Wie sieht es unter der Haube aus? 3 $file = ; 4 $line = ; Wurde in einem früheren Aufruf von papaya_page::sendheader() mittels headers_ sent() festgestellt, dass Header ausgegeben worden sind, ist $headersenttrue und nichts weiter geschieht: Listing 2.63: Auf Headerausgabe prüfen 5 if (isset($headerssent) && $headerssent) { 6 //already sent some headers and reported an error 7 return FALSE; Wenn keine Header ausgegeben worden sind, wird überprüft, ob dies mittlerweile geschehen ist. Wenn ja, enthalten $file und $line die Information, in welcher Zeile und in welcher Datei die Header ausgegeben worden sind: Listing 2.64: Headerausgabe bei Fehlern protokollieren 8 } elseif ($headerssent = headers_sent($file, $line)) { 9 //report the error to log 10 $errormsg = WARNING #2 Cannot modify header information - headers already sent ; 11 $this->logmsg(msg_warning, 9, $errormsg, $errormsg. in.$file. :.$line, TRUE, 2); 12 return FALSE; Wurden noch keine Header ausgegeben, wird geprüft, ob die Konfigurationsoption PAPA- YA_DISABLE_XHEADERS gesetzt und TRUE ist. Wenn ja, werden alle Header-Zeilen nicht ausgegeben, die mit X- beginnen und via papaya_page::sendheader() gesendet werden sollen: Listing 2.65: X-Header-Ausgabe unterdrücken 13 } else { 14 if (defined( PAPAYA_DISABLE_XHEADERS ) && PAPAYA_DISABLE_XHEADERS && 15 strtoupper(substr($headerstr, 0, 2)) == X- ) { 16 return 0; 17 } 18 header($headerstr); 19 } 20 return 0; 21 } Damit wird verhindert, dass z.b. der X-Generator-Header Aufschluss über das verwendete Content-Management-System gibt. Andere von papaya CMS generierte X-Header dienen der Fehleranalyse. Damit lassen sich z.b. Weiterleitungen nachvollziehen und in geringem Umfang debuggen. Im folgenden Abschnitt wird beschrieben, wie die Systemoptionen für papaya CMS aus der Datenbank gelesen werden. 39

44 2 Wie funktioniert eigentlich papaya CMS? Kongurationsoptionen aus der Datenbank laden (base_options.php) Die Klasse base_options enthält die von papaya CMS verwendeten Konstanten und initalisiert sie. Dazu gehören auch die Konstanten für die Basistabellen. Diese Konstanten werden verwendet, um Konfigurationsoptionen im ganzen System einheitlich auslesen zu können und um die Namen der Basistabellen zentral zu definieren.! Verwenden Sie bitte nicht PAPAYA_DB_TABLEPREFIX. _lng oder ähnliches für Basistabellen, sondern immer die vollständige Konstante, sofern diese vorhanden ist. Dadurch können die Tabellen später umbenannt werden, ohne die einzelnen Module anpassen zu müssen. Eine Liste der Konstanten mit den Tabellennamen finden Sie in Abschnitt 2.3.5, S. 42. Die Klasse base_options schrittweise erklärt Die Klasse base_options erweitert base_db. Da viele Optionen im Backend von papaya CMS bequem über eine Benutzeroberfläche bearbeitet werden können, wird eine Datenbankkonnektivität benötigt: Abbildung 2.6: UML-Diagramm der Klasse base_options 40

45 2.3 Wie sieht es unter der Haube aus? Zu Beginn der Klasse werden einige Klassenattribute gesetzt. So wird in $tableoptions der Name der Optionstabelle gespeichert. Dieser wird in der conf.inc.php in der Konstanten PAPAYA_DB_TBL_OPTIONS definiert und in dieser Klasse lediglich als Attribut zugewiesen. Die folgenden Attribute $options, $optiongroups sowie $optlinks werden in der von base_options abgeleiteten Klasse papaya_options verwendet. Systemoptionen in der Klasse base_options Die wichtigsten Attribute dieser Klasse sind $optfields und $tables. Diese enthalten Struktur und Standardwerte der Konfigurationsoptionen von papaya CMS. Eine Liste aller Konfigurationsoptionen ist im Administratorhandbuch zu finden. Dort werden sie auch ausführlich erklärt. Das folgende Beispiel stellt vor, wie Konfigurationsoptionen im Array $optfields definiert sind: Listing 2.66: Beispiel für eine Konfigurationsoption in $optfields 1 var $optfields = array( PAPAYA_DBG_DATABASE_ERROR => array(3, isnum, combo, array(1 => on, 0 => off ), 1) 4 ); Der Array-Schlüssel ist der spätere Konstantenname. Der Wert des Arrays ist wieder ein Array. Es funktioniert ähnlich wie das $editfields-array für Module, enthält statt des Titels jedoch eine Gruppen-ID, über die die Option einer Optionsgruppe zugeordnet wird. Tabelle 2.4: Aufbau des Werte-Arrays von base_options::optfields Attributschlüssel Standardwert 0 Gruppen-ID 1 Funktion für Validitätsprüfungen (checkit) 2 Eingabetyp 3 Konfigurationsoption für den Eingabetyp 4 Standardwert Die Gruppen sind in der Methode base_statictables::gettableoptgroups() festgelegt. In der folgenden Tabelle sind alle Optionsgruppen definiert, die Sie auch in der Systemkonfiguration im papaya-backend finden können: 41

46 2 Wie funktioniert eigentlich papaya CMS? Tabelle 2.5: Liste der verfügbaren Optionsgruppen Gruppen-ID Gruppenname 0 Unbekannt 1 Tabellen (ungenutzt) 2 Dateien und Verzeichnisse 3 Fehlersuche 4 Language (ungenutzt) 5 Projektoptionen 6 Internes (ungenutzt) 7 System 8 Layout 9 Standardseiten 10 Zeichensätze 11 Übersichtsseite 12 Anmeldung 13 Support 14 MediaDB 15 Cache 16 Protokoll Tabellendenitionen in der Klasse base_options Die Datenbanktabellen des Basissystems werden alle im Array $tables der Klasse base_ options gespeichert. Im folgenden Code-Beispiel ist dargestellt, wie eine Datenbanktabelle aufgeführt wird: Listing 2.67: Beispiel für eine Tabellendefinition im Array $tables 1 var $tables = array( 2 PAPAYA_DB_TBL_LNG => lng, 3 ); Als Schlüssel wird wieder der Konstantenname verwendet. Der Wert ist der Tabellenname ohne das Standardpräfix papaya_. In der Methode papaya_options::definedatabasetab ) erhalten die Konstantennamen für die Tabellen den vollständigen Tabellennamen. 42

47 2.3 Wie sieht es unter der Haube aus? Die folgende Tabelle listet alle Datenbanktabellen auf, die in der Klasse base_options definiert werden: Tabelle 2.6: Tabellenkonstanten in base_options Feldbeschriftung Bedeutung PAPAYA_DB_TBL_AUTHGROUPS auth_groups PAPAYA_DB_TBL_AUTHIP auth_ip PAPAYA_DB_TBL_AUTHLINK auth_link PAPAYA_DB_TBL_AUTHMODPERMLINKS auth_modperm_link PAPAYA_DB_TBL_AUTHMODPERMS auth_modperm PAPAYA_DB_TBL_AUTHOPTIONS auth_useropt PAPAYA_DB_TBL_AUTHPERM auth_perm PAPAYA_DB_TBL_AUTHTRY auth_try PAPAYA_DB_TBL_AUTHUSER auth_user PAPAYA_DB_TBL_BOX box PAPAYA_DB_TBL_BOXGROUP boxgroups PAPAYA_DB_TBL_BOXLINKS boxlinks PAPAYA_DB_TBL_BOX_PUBLIC box_public PAPAYA_DB_TBL_BOX_PUBLIC_TRANS box_public_trans PAPAYA_DB_TBL_BOX_TRANS box_trans PAPAYA_DB_TBL_BOX_VERSIONS box_versions PAPAYA_DB_TBL_BOX_VERSIONS_TRANS box_versions_trans PAPAYA_DB_TBL_CRONJOBS cronjobs PAPAYA_DB_TBL_DATAFILTER datafilter PAPAYA_DB_TBL_DATAFILTER_LINKS datafilter_links PAPAYA_DB_TBL_DOMAINS domains PAPAYA_DB_TBL_IMAGES images PAPAYA_DB_TBL_IMPORTFILTER importfilter PAPAYA_DB_TBL_IMPORTFILTER_LINKS importfilter_links PAPAYA_DB_TBL_LINKTYPES linktypes PAPAYA_DB_TBL_LNG lng PAPAYA_DB_TBL_LOCKING locking PAPAYA_DB_TBL_LOG log PAPAYA_DB_TBL_LOG_QUERIES log_queries 43

48 2 Wie funktioniert eigentlich papaya CMS? Tabelle 2.6: Tabellenkonstanten in base_options (forts.) Feldbeschriftung Bedeutung PAPAYA_DB_TBL_MEDIADB_FILES mediadb_files PAPAYA_DB_TBL_MEDIADB_FILES_DERIVATIONS mediadb_files_derivations PAPAYA_DB_TBL_MEDIADB_FILES_TRANS mediadb_files_trans PAPAYA_DB_TBL_MEDIADB_FILES_VERSIONS mediadb_files_versions PAPAYA_DB_TBL_MEDIADB_FOLDERS mediadb_folders PAPAYA_DB_TBL_MEDIADB_FOLDERS_PERMISSIONS mediadb_folders_permissions PAPAYA_DB_TBL_MEDIADB_FOLDERS_TRANS mediadb_folders_trans PAPAYA_DB_TBL_MEDIADB_MIMEGROUPS mediadb_mimegroups PAPAYA_DB_TBL_MEDIADB_MIMEGROUPS_TRANS mediadb_mimegroups_trans PAPAYA_DB_TBL_MEDIADB_MIMETYPES mediadb_mimetypes PAPAYA_DB_TBL_MEDIADB_MIMETYPES_EXTENSIONS mediadb_mimetypes_extensions PAPAYA_DB_TBL_MEDIA_FILES media_files PAPAYA_DB_TBL_MEDIA_FILES_TRANS media_files_trans PAPAYA_DB_TBL_MEDIA_FOLDERS media_folders PAPAYA_DB_TBL_MEDIA_FOLDERS_TRANS media_folders_trans PAPAYA_DB_TBL_MEDIA_LINKS media_links PAPAYA_DB_TBL_MESSAGES messages PAPAYA_DB_TBL_MIMETYPES mimetypes PAPAYA_DB_TBL_MODULEGROUPS modulegroups PAPAYA_DB_TBL_MODULEOPTIONS moduleoptions PAPAYA_DB_TBL_MODULES modules PAPAYA_DB_TBL_PHRASE phrase PAPAYA_DB_TBL_PHRASE_LOG phrase_log PAPAYA_DB_TBL_PHRASE_MODULE phrase_module PAPAYA_DB_TBL_PHRASE_MODULE_REL phrase_relmod PAPAYA_DB_TBL_PHRASE_TRANS phrase_trans PAPAYA_DB_TBL_SPAM_CATEGORIES spamcategories PAPAYA_DB_TBL_SPAM_IGNORE spamignore PAPAYA_DB_TBL_SPAM_LOG spamlog PAPAYA_DB_TBL_SPAM_REFERENCES spamreferences PAPAYA_DB_TBL_SPAM_STOP spamstop 44

49 2.3 Wie sieht es unter der Haube aus? Tabelle 2.6: Tabellenkonstanten in base_options (forts.) Feldbeschriftung Bedeutung PAPAYA_DB_TBL_SPAM_WORDS spamwords PAPAYA_DB_TBL_SURFER surfer PAPAYA_DB_TBL_SURFERACTIVITY surferactivity PAPAYA_DB_TBL_SURFERBLACKLIST surferblacklist PAPAYA_DB_TBL_SURFERCHANGEREQUESTS surferchangerequests PAPAYA_DB_TBL_SURFERCONTACTCACHE surfercontactcache PAPAYA_DB_TBL_SURFERCONTACTDATA surfercontactdata PAPAYA_DB_TBL_SURFERCONTACTPUBLIC surfercontactpublic PAPAYA_DB_TBL_SURFERCONTACTS surfercontacts PAPAYA_DB_TBL_SURFERDATA surferdata PAPAYA_DB_TBL_SURFERDATACLASSES surferdataclasses PAPAYA_DB_TBL_SURFERDATACLASSTITLES surferdataclasstitles PAPAYA_DB_TBL_SURFERDATATITLES surferdatatitles PAPAYA_DB_TBL_SURFERFAVORITES surferfavorites PAPAYA_DB_TBL_SURFERGROUPS surfergroups PAPAYA_DB_TBL_SURFERLISTS surferlists PAPAYA_DB_TBL_SURFERPERM surferperm PAPAYA_DB_TBL_SURFERPERMLINK surferlinks PAPAYA_DB_TBL_TAG tag PAPAYA_DB_TBL_TAG_CATEGORY tag_category PAPAYA_DB_TBL_TAG_CATEGORY_PERMISSIONS tag_category_permissions PAPAYA_DB_TBL_TAG_CATEGORY_TRANS tag_category_trans PAPAYA_DB_TBL_TAG_LINKS tag_links PAPAYA_DB_TBL_TAG_TRANS tag_trans PAPAYA_DB_TBL_TODOS todos PAPAYA_DB_TBL_TOPICS topic PAPAYA_DB_TBL_TOPICS_PUBLIC topic_public PAPAYA_DB_TBL_TOPICS_PUBLIC_TRANS topic_public_trans PAPAYA_DB_TBL_TOPICS_TRANS topic_trans PAPAYA_DB_TBL_TOPICS_VERSIONS topic_versions PAPAYA_DB_TBL_TOPICS_VERSIONS_TRANS topic_versions_trans 45

50 2 Wie funktioniert eigentlich papaya CMS? Tabelle 2.6: Tabellenkonstanten in base_options (forts.) Feldbeschriftung Bedeutung PAPAYA_DB_TBL_URLS urls PAPAYA_DB_TBL_VIEWLINKS viewlinks PAPAYA_DB_TBL_VIEWMODES viewmodes PAPAYA_DB_TBL_VIEWS views Die Methode papaya_options::loadanddefine() ist die einzige von außen aufgerufene Methode dieser Klasse. Der Aufruf erfolgt im Konstruktor von papaya_page. Die Methode loadanddefine() führt folgende Schritte aus: 1. Aus der Optionstabelle in der Datenbank werden alle installationsspezifischen Werte der Konfigurationsoptionen ausgelesen und als Konstanten definiert. Dazu wird die Klassenmethode base_options::define() benutzt. 2. base_options::define() definiert nur diejenigen Optionen, die noch nicht per define() definiert worden sind. Damit erhalten alle Systemoptionen Vorrang, die beispielsweise in der conf.inc.php definiert worden sind. 3. Anschließend werden die Standardwerte aus dem Array $optfields gelesen. Wenn für eine Systemoption aus diesem Array kein Wert aus der Datenbank gefunden worden ist und sie folglich noch nicht definiert werden konnte, werden die Konstanten mit dem Standardwert aus diesem Array initialisiert. 4. Im nächsten Schritt werden für das Protokoll-Objekt und das Übersetzungsobjekt Namen im globalen Namensraum vergeben: Listing 2.68: Protokoll- und Übersetzungsobjekt in den globalen Namensraum setzen 1 $this->define( PAPAYA_GLOBAL_LOGOBJECT, PAPAYA_LOG_OBJECT ); 2 $this->define( PAPAYA_GLOBAL_PHRASEOBJECT, PAPAYA_PHRASE_TRANSLATOR ); 5. Nun werden die ganzen Pfadkonstanten gesetzt: Listing 2.69: Pfadkonstanten im globalen Namensraum 1 $this->define( PAPAYA_MODULES_PATH, PAPAYA_INCLUDE_PATH. modules/ ); 2 $this->define( PAPAYA_PATH_CACHE, PAPAYA_PATH_DATA. cache/ ); 3 $this->define( PAPAYA_PATH_MEDIAFILES_OLD, PAPAYA_PATH_DATA. media_db/ ); 4 $this->define( PAPAYA_PATH_THUMBFILES_OLD, PAPAYA_PATH_DATA. media_thumbs/ ); 5 $this->define( PAPAYA_PATH_MEDIAFILES, PAPAYA_PATH_DATA. media/files/ ); 6 $this->define( PAPAYA_PATH_THUMBFILES, PAPAYA_PATH_DATA. media/thumbs/ ); 7 $this->define( PAPAYA_PATH_TEMPLATES, PAPAYA_PATH_DATA. templates/. 8 PAPAYA_LAYOUT_TEMPLATES. / ); 9 $path = str_replace( //, /, PAPAYA_PATH_WEB.PAPAYA_PATH_ADMIN. / ); 10 $this->define( PAPAYA_PATHWEB_ADMIN, $path); Die Pfadkonstanten ersparen es Ihnen als Entwickler, alle Pfade manuell zusammensetzen zu müssen. Pfadkonstanten erlauben zudem eine gewisse Flexibilität, wenn Verzeichnisstrukturen geändert werden, da die Basispfade alle zentral verwaltet werden. 46

51 2.3 Wie sieht es unter der Haube aus? 6. Im letzten Schritt wird die Methode base_options::definedatabasetables( ) ausgeführt. Diese Methode iteriert alle in $this->tables angelegten Konstantenund Tabellennamen und definiert diese Konstanten. Bei der Definition wird das Tabellenpräfix aus der Konstanten PAPAYA_DB_TABLEPREFIX mit dem Tabellennamen verknüpft: Listing 2.70: Konstanten der Tabellennamen definieren 1 foreach ($this->tables as $optionname => $opt) { 2 if (isset($opt)) { 3 $this->define($optionname, PAPAYA_DB_TABLEPREFIX. _.$opt); 4 } 5 }! Optionen, die in der conf.inc.php definiert worden sind, haben stets Vorrang vor den in papaya_options definierten Optionen. Dies hat einen einfachen Grund: Stellen SIe sich vor, Sie möchten einen Datenbank-Dump von Ihrem Live-Server auf Ihren Entwicklungsserver einspielen. Auf dem Live-Server haben Sie die Option PAPA- YA_UI_SECURE auf on gesetzt, sodass Sie nur per HTTPS in das Backend von papaya CMS gelangen können. Da jedoch auf Ihrem Entwicklugnsserver kein HTTPS definiert ist, können Sie sich nicht mehr einloggen. Dieses Problem lösen Sie dadurch, dass Sie die Option in der conf.inc.php definieren und auf off setzen. Hinweise zu den Pfadkonstanten in papaya CMS! Bitte benutzen Sie auf jeden Fall die Pfadkonstanten und lassen Sie sich nicht darauf ein, Pfade manuell zu kodieren. Wenn Sie beispielsweise davon ausgehen, dass das Backend immer unter dem lokalen Webpfad /papaya zu erreichen ist und diesen Pfad hart kodieren, werden Sie direkt Probleme bekommen, wenn papaya CMS in ein Unterverzeichnis installiert wird. Ihr Modul wird nicht richtig oder überhaupt nicht mehr funktionieren, da die Pfade nicht mehr stimmen. Konstantenname PAPAYA_MODULES_PATH PAPAYA_PATH_CACHE PAPAYA_PATH_MEDIAFILES_OLD PAPAYA_PATH_THUMBFILES_OLD PAPAYA_PATH_MEDIAFILES Tabelle 2.7: Liste der definierten Pfad-Konstanten Erläuterung Absoluter Pfad zum Modul-Verzeichnis. Absoluter Pfad zum Cache-Verzeichnis. Alter Pfad zur MediaDB, wird bei der Konvertierung benötigt. Alter Pfad zu den Thumbnails (eigentlich nicht notwendig). Absoluter Pfad zu den MediaDB-Dateien. 47

52 2 Wie funktioniert eigentlich papaya CMS? Konstantenname PAPAYA_PATH_THUMBFILES PAPAYA_PATH_TEMPLATES PAPAYA_PATHWEB_ADMIN Tabelle 2.7: Liste der definierten Pfad-Konstanten (forts.) Erläuterung Absoluter Pfad zu den Thumbnails. Absoluter Pfad zu den Templates. Relativer Pfad zum Backend dieser papaya-installation Seiten-Content für Preview-Modus und Frontend ausgeben In der Methode papaya_page::createtopic() wird die Instanz einer Topic-Klasse angelegt und im Attribut papaya_page::topic gespeichert. Als Topic-Objekt wird eine Instanz der Klasse papaya_topic oder papaya_publictopic eingesetzt, die von base_topic_edit abgeleitet ist. Wenn ein Redakteur im Vorschaumodus die Seite aufruft, wird papaya_topic instanziiert. Für das Frontend wird die Klasse papaya_publictopic eingebunden. Die Hierarchie der Topic-Klassen ist im folgenden UML-Diagramm dargestellt: 48

53 2.3 Wie sieht es unter der Haube aus? Abbildung 2.7: Vererbungshierarchie von papaya_topic und papaya_topic_public Das Topic-Objekt als Hüllenklasse für Content-Module Das Topic-Objekt ist eine Hüllenklasse für bestimmte Content-Klassen, die von base_plugin abgeleitet sind. Im Topic-Objekt wird die Content-Klasse instanziiert, die mit der Ansicht der aktuellen Seite verknüpft ist. Anschließend werden die Schnittstellen für die Dateneinund ausgabe angesprochen. 49

54 2 Wie funktioniert eigentlich papaya CMS? Die Schnittstelle für die Dateneingabe ist das Eingabeformular Inhalt bearbeiten, das in der Seitenansicht im papaya-backend dargestellt wird. Dieses Formular wird in den Content-Klassen im Array $editfields definiert, siehe Abschnitt 3.1.4, S. 64. Um das Formular darzustellen, wird in der Klasse base_topic_edit die Methode geteditcontent( ) aufgerufen. Diese ruft wiederum die Methode getform() des Content-Moduls auf. getform() gibt die Repräsentation des Eingabeformulars als XML aus. Dieses XML wird für das Backend als Eingabeformular transformiert. Die Schnittstelle für die Datenausgabe besteht in der Methode parsecontent() des Topic-Objekts. Diese Methode liest die Daten aus dem Content-Modul aus und gibt den Inhaltsteil des Seiten-XMLs zurück. Ferner ist das Topic-Objekt für die Verwaltung der Metadaten einer Seite verantwortlich. Dazu gehören folgende Informationen: Sprachunabhängige Seiteneigenschaften wie die Seiten-ID, seitenspezifische Standard- Sprache, sowie alle Eigenschaften, die in der Seitenansicht in der Administration von papaya CMS unter Eigenschaften verwaltet werden können. Die Liste der Sprachversionen der Seite. Die ID der Ansicht, die in der aktuellen Sprachversion der Seite benutzt wird. Ausgabe des Seiteninhalts im Detail Das folgende Sequenzdiagramm stellt vor, wie das Topic-Objekt instanziiert wird. Ferner beschreibt das Diagramm im Detail, welche Objekte bei der Ausgabe des Seiteninhalts beteiligt sind und wie sie miteinander interagieren: 50

55 2.3 Wie sieht es unter der Haube aus? Abbildung 2.8: Sequenzdiagramm! Hinweis zum SequenzdiagrammIn Abbildung 2.8, S. 51 wird anstelle der Klassen papaya_topic oder papaya_publictopic die Vaterklasse base_topic benutzt. Im ersten Schritt wird in der Methode createtopic() der Klasse papaya_page eine Instanz des Topic-Objekts erzeugt. Die Instanz wird im Attribut papaya_page::topic gespeichert. Anschließend wird überprüft, ob die Seite in der aktuellen Sprachversion konfiguriert ist. Dies wird mit der Methode base_topic::topicexists() überprüft. Im folgenden Schritt wird versucht, den Seiteninhalt aus dem Cache zu lesen. Wenn dies fehlschlägt, wird die Methode papaya_page::getpage() aufgerufen. Mit dieser Methode werden erst alle Metadaten des Topic-Objekts ausgelesen, indem $topic->loadoutput( ) ausgeführt wird. 51

56 2 Wie funktioniert eigentlich papaya CMS? Mit der Methode checkpublishperiod() aus der Klasse papaya_publictopic bzw. papaya_topic wird überprüft, ob das aktuelle Datum innerhalb des Veröffentlichungszeitraums der Seite liegt. Im Frontend sollen die Seiteninhalte nur dann ausgegeben werden, wenn sie veröffentlicht worden sind. Daher wertet die Methode checkpublishperio ) der Klasse papaya_publictopic alle Datumsangaben für den Veröffentlichungszeitraum aus und gibt nur dann TRUE zurück, wenn die Seite öffentlich gestellt ist. In papaya_ topic gibt die Methode checkpublishperiod() stets TRUE zurück, da diese Klasse für den Vorschaumodus von papaya CMS zuständig ist. Mit $topic->getviewid() wird die ID der Ansicht ausgelesen und dem Ausgabefilter übergeben. Anschließend wird in papaya_page eine Instanz des Layoutobjekts angelegt, das als Wrapper für den XSLT-Prozessor fungiert. Diesem Objekt soll nun das Seiten-XML übergeben werden. Zu diesem Zweck wird die Methode parsecontent() des Topic- Objekts $topic aufgerufen. Content-Modul instanziieren und Seiteninhalte auslesen Im Topic-Objekt wird in der Methode parsecontent() das Content-Modul instanziiert. Dazu wird die statische Methode getplugininstance() der Klasse base_pluginloader benutzt. Die Instanz des Content-Moduls wird im Klassenattribut $moduleobj gespeichert. Die Instanz wird benutzt, um den Inhalt der Seite aus der Datenbank zu laden und als XML auszugeben. Zu diesen Zweck werden die Methoden getparseddata() und getparsedteaser() des Content-Moduls ausgelesen. getparsedteaser() liest den Teaser der Seite aus, getparseddata() den Hauptinhalt. Die XML-Ausgaben dieser Methoden werden in ein XML-Element eingebettet und an die aufrufende Instanz zurückgegeben. XML der Seitenausgabe an Ausgabelter übergeben Das XML wird in der Methode generatepage() der Klasse papaya_page direkt an das Layoutobjekt übergeben. Zudem werden weitere Inhalte wie Metadaten, Ansichtenlisten für die aktuelle Seite sowie die unterschiedlichen Sprachversionen im Layoutobjekt gesetzt. Ebenso werden entsprechende Parameter für die XSLT-Transformation gesetzt. papaya_output::getfilter erzeugt eine Instanz des Ausgabefilters. Der Ausgabefilter liest den Pfad zum XSLT-Stylesheet aus, die in der Ansicht gespeichert ist. Anschließend wird der Transformationsprozess gestartet. Dazu wird die Methode parsepage() ausgeführt. Diese Methode wird in base_outputfilter definiert und von den implementierenden Klassen überladen. Die Seite wird im entsprechenden Zielformat ausgegeben. Unab- 52

57 2.3 Wie sieht es unter der Haube aus? hängig davon wurden die Header bereits in der Methode getpageoutput() sowie in getpage() in der Klasse papaya_page gesetzt. 53

58 2 Wie funktioniert eigentlich papaya CMS? 54

59 3 Basismodule für papaya CMS programmieren In diesem Kapitel erfahren Sie, wie Sie einfache Content-Module, Boxen und Seiten, selber entwickeln können. Zu Beginn wird beschrieben, wie die Verzeichnisstruktur für Pakete aufgebaut ist und welche Dateien Sie benötigen, um Module in papaya CMS registrieren und benutzen zu können. Anschließend lernen Sie schrittweise die Entwicklung von Boxen- und Seitenmodulen. Das folgende Klassendiagramm stellt alle Basisklassen vor, die Sie für eigene Module erweitern können: Abbildung 3.1: Klassenstruktur papaya CMS 3.1 Box- und Seitenmodule programmieren Box- und Seitenmodule gehören zu den einfachsten Modulen, die man in papaya CMS entwickeln kann. Da in den Basismodulen für Boxen und Seiten bereits alle Schnittstellen für 55

60 3 Basismodule für papaya CMS programmieren die Benutzereingabe sowie für die Datenausgabe implementiert sind, beschränkt sich der Entwicklungsaufwand auf das Überladen einiger Funktionen, mit denen Inhalte ausgegeben werden Moduleinbindung vorbereiten Damit Sie während der Entwicklung Ihr Modul testen können, müssen Sie es in papaya CMS registrieren. Dazu gehen Sie wie folgt vor: 1. Legen Sie unterhalb von./papaya-lib/modules/ ein Verzeichnis an, in das die PHP-Quellcodedateien gespeichert werden. 2. Erstellen Sie in diesem Verzeichnis eine Datei mit dem Namen modules.xml. Kopieren Sie dazu einfach folgenden Inhalt in die Datei: Listing 3.1: Minimale modules.xml anlegen 1 <?xml version="1.0"?> 2 <modulegroup> 3 <name>example</name> 4 <description>example box and page module</description> 5 <modules> 6 <module type="box" 7 guid="9e0a3e aa71831c3fbdd" 8 name="my Box" 9 class="actbox_example" 10 file="actbox_example.php" 11 outputfilter="yes"></module> 12 <module type="page" 13 guid="ba4b97036af3b67fe2649ac679cb9fe0" 14 name="my Page" 15 class="content_example" 16 file="content_example.php" 17 outputfilter="yes"></module> 18 </modules> 19 </modulegroup> Passen Sie den Namen von Dateien und Klassen an Ihre eigenen Module an. Ändern Sie die GUIDs, indem Sie andere md5-summen verwenden. Stellen Sie sicher, dass die von ihnen gewählten Namen für die Klassen und Dateien mit denen in der modules.xml übereinstimmen. 3. Nachdem Sie die entsprechenden Quellcodedateien angelegt haben, können Sie im Backend von papaya CMS den Modulscan ausführen. Dabei wird die modules.xml in die Datenbank eingelesen und die Module werden registriert. 56

61 3.1 Box- und Seitenmodule programmieren! Näheres zu den verschiedenen Modultypen und zur Struktur der modules.xml erfahren Sie in Abschnitt 3.4.3, S. 91. Sie müssen auf jeden Fall einen Modulscan ausführen, damit die in der modules. xml angegebenen Module in papaya CMS registriert werden. Andernfalls können Sie die Module weder benutzen noch testen Boxmodule programmieren Ein Boxmodul ist das einfachste Content-Modul in papaya CMS. Es besteht aus einer Klasse, die von der Basisklasse base_actionbox abgeleitet ist. Folgende Schritte sind notwendig, um eine eigene Box zu erstellen: 1. Erstellen Sie eine PHP-Datei und importieren Sie die Klasse base_actionbox aus dem Basissystem. 2. Überladen Sie das Attribut $preview, um festzulegen, ob die Box eine Vorschaufunktion unterstützen soll oder nicht. 3. Überladen Sie das Klassenattribut $editfields, um Eingabefelder für das Backend zu erstellen. 4. Überladen Sie die Funktion getparseddata(), um die Ausgabe der Boxinhalte zu bestimmen. 5. Registrieren Sie die Klasse in der modules.xml, siehe Abschnitt 3.4.3, S. 91. In den folgenden Abschnitten werden die einzelnen Schritte im Detail erläutert. Klasse base_actionbox einbinden Laden Sie mit der PHP-Funktion require_once() die Datei, die die notwendige Elternklasse base_actionbox enthält. Den Pfad zum Basissystem papaya-lib/ können Sie aus der Konstanten PAPAYA_INCLUDE_PATH auslesen, die in der conf.inc.php definiert ist: 1 <?php 2 Listing 3.2: Die Klasse base_actionbox einbinden 3 require_once(papaya_include_path. system/base_actionbox.php ); 4 5 class actbox_example extends base_actionbox { 6 } 7?> 57

62 3 Basismodule für papaya CMS programmieren Leiten Sie Ihre Klasse von der die Basisklasse base_actionbox ab.! Warum require once()undnichtinclude o nce()?require o nce()include o nce()derwesentlicheunte onceerzeugteineeerror F ehlermeldung(f atalerror), whrendinclude_ oncelediglicheinew arnung(ewarning)ausgibt.esistgngigerpapaya P rogrammierstil, dassexternedateienvorderklassendeklarationperrequire_ onceeingebundenwerden, damitentwicklersof ortauf einef alscheingebundenedateihingew Innerhalb von Methodenbllöcken wird hingegen include_once() benutzt, damit das laufende Programm nicht direkt mit einem Fatal Error abbricht, wenn die entsprechende Methode aufgerufen wird und die inkludierte Datei nicht gelanden werden kann. Attribute $preview und $editfields überladen Das Attribut $preview nimmt einen booleschen Wert an und hat die Funktion eines Flags. Hat $preview den Wert TRUE, kann die Box im Preview-Modus angeschaut werden, andernfalls nicht. 1 <?php 2 Listing 3.3: Das Attribut $preview überladen 3 require_once(papaya_include_path. system/base_actionbox.php ); 4 5 class actbox_example extends base_actionbox { 6 $preview = TRUE; 7 } 8?> Das Attribut $editfields ist ein Array, in dem die Felder für die Eingabemaske Inhalt bearbeiten definiert werden. Diese Eingabemaske kommt zur Anwendung, wenn Sie im Backend von papaya CMS eine Box mit diesem Modul anlegen. Das Array $editfields ist ein zweidimensionales Array, dessen erste Ebene die Schlüssel für Eingabemaske und Daten enthält. 1 <?php 2 Listing 3.4: Das Attribut $editfields überladen 3 require_once(papaya_include_path. system/base_actionbox.php ); 4 5 class actbox_example extends base_actionbox { 6 $preview = TRUE; 7 8 $editfields = array( 9 title => array( Title, issometext, FALSE, input, 200), 10 text => array( Text, issometext, FALSE, textarea, 15) 11 ); 12 } 58

63 3.1 Box- und Seitenmodule programmieren 13?> Die Felder im inneren Array bestimmen die Art des jeweiligen Eingabefeldes. Näheres zum Array $editfields erfahren Sie in Abschnitt 3.1.4, S. 64. Die Schlüssel title und text werden intern dazu benutzt, um auf die entsprechenden Felder zuzugreifen. Wenn der Nutzer über die Eingabemaske Daten eingibt, stehen diese Daten im Array $this->data zur Verfügung. In diesem Fall können die Schlüssel der jeweiligen Felder dazu verwendet werden, die eingegebenen Daten aus dem Array $this- >data auszulesen. Die Methode getparseddata() überladen Die Methode getparseddata() wird aufgerufen, um den Inhalt des Moduls auszugeben. Durch Überladen der Methode bestimmen Sie den auszugebenden Inhalt: 1 <?php 2 Listing 3.5: Methode getparseddata() überladen 3 require_once(papaya_include_path. system/base_actionbox.php ); 4 5 class actbox_example extends base_actionbox { 6 $preview = TRUE; 7 8 $editfields = array( 9 title => array( Title, issometext, FALSE, input, 200), 10 text => array( Text, issometext, FALSE, textarea, 15) 11 ); function getparseddata() { 14 $this->setdefaultdata(); 15 $result = <example>.lf; 16 $result.= sprintf( <title>%s</title>.lf, 17 papaya_strings::escapehtmlchars($this->data[ title ])); 18 $result.= sprintf( <text>%s</text>.lf, 19 $this->getxhtmlstring($this->data[ text ])); 20 $result.= </example>.lf; 21 return $result; 22 } 23 } 24?> Die Inhaltsdaten für eine Box werden vom Benutzer im Backend unter Inhalt bearbeiten eingegeben. Das Eingabeformular ist über die $editfields definiert. papaya CMS liest diese Daten automatisch aus der Datenbank aus und lädt sie in das assoziative Array $ this->data. Sie können auf die Daten zuzugreifen, indem Sie mit den Schlüsseln der Felder im Array $editfields das Array $this->data auslesen. 59

64 3 Basismodule für papaya CMS programmieren! Standard-Daten in das Array this > dataladenthis->datawenn keine Daten eingegeben wurden, ist das Array $this->data leer. Der Versuch, mit den entsprechenden Schlüsseln auf die Feldwerte zuzugreifen, löst eine Notice aus. Um das zu verhindern, gehen Sie wie folgt vor:geben Sie für jedes Feld in den $editfields immer einen Standardwert ein. Rufen Sie in der Methode getparseddata() als erstes die Methode $this->setdefaultdata() auf. Damit wird das Array $this->data mit den Standardwerten gefüllt, die in den $editfields angegeben sind. Wenn Sie die Inhalte der Felder ausgeben, müssen diese maskiert werden. Dafür wird im Quellcode-Beispiel die Methode papaya_strings::escapehtmlchars() verwendet. Für den Haupttext wird die Methode base_object::getxhtmlstring() verwendet. Näheres dazu erfahren Sie in Abschnitt 3.3, S. 78. Als letzten Schritt tragen Sie das Boxmodul wie in Abschnitt 3.4.3, S. 91 beschrieben in die modules.xml ein. Nachdem Sie in der Modulverwaltung den Modulscan durchgeführt haben, wird das neue Modul erkannt und kann verwendet werden Seitenmodule programmieren Ein Seitenmodul zu entwickeln ist fast so einfach wie das Entwickeln eines Boxmoduls. Da die Standardfunktionen bereits in den Basisklassen implementiert sind, müssen Sie lediglich die Methoden getparsedteaser() und getparseddata() sowie das Attribut $editfields überladen. Folgende Schritte sind notwendig, um ein Seitenmodul zu erstellen: 1. Erstellen Sie eine PHP-Datei und importieren Sie die Klasse base_content aus dem Basissystem. 2. Überladen Sie das Klassenattribut $editfields, um ein Eingabeformular für das Backend zu erstellen. 3. Überladen Sie die Methode getparseddata(), um die Inhalte für die Seite auszugeben. 4. Überladen Sie die Methode getparsedteaser(), um die Inhalte für den Teaser auszugeben. 5. Registrieren Sie die Klasse in der modules.xml, siehe Abschnitt 3.4.3, S. 91. In den folgenden Abschnitten werden die einzelnen Schritte im Detail erläutert. 60

65 3.1 Box- und Seitenmodule programmieren Einbinden der Klasse base_content in das eigene Seitenmodul Laden Sie die Datei der notwendigen Elternklasse base_content über die PHP-Funktion require_once(). Den Pfad zum Basissystem papaya-lib/ können Sie aus der Konstanten PAPAYA_INCLUDE_PATH auslesen, die in der conf.inc.php definiert ist: 1 <?php 2 Listing 3.6: Die Klasse base_content einbinden 3 require_once(papaya_include_path. system/base_content.php ); 4 5 class content_example extends base_content { 6 } 7?> Das Attribut $editfields ist ein Array, in dem die Felder für die Eingabemaske Inhalt bearbeiten definiert werden. Diese Eingabemaske kommt zur Anwendung, wenn Sie im Backend von papaya CMS eine Seite mit diesem Modul anlegen. Das Array $editfields ist ein zweidimensionales Array, dessen erste Ebene die Schlüssel für Eingabemaske und Daten enthält. 1 <?php 2 Listing 3.7: Das Attribut $editfields überladen 3 require_once(papaya_include_path. system/base_content.php ); 4 5 class content_example extends base_content { 6 7 $editfields = array( 8 title => array( Title, issometext, TRUE, input, 200,, ), 9 teaser => array( Teaser, issometext, FALSE, simplerichtext, 5,, ), 10 text => array( Text, issometext, FALSE, richtext, 15,, ) 11 ); 12 } 13?> Die Felder im inneren Array bestimmen die Art des jeweiligen Eingabefeldes. Näheres zum Array $editfields erfahren Sie in Abschnitt 3.1.4, S. 64. Die Schlüssel title und text werden intern dazu benutzt, auf die entsprechenden Felder zuzugreifen. Wenn der Nutzer über die Eingabemaske Daten eingibt, stehen diese Daten im Array $this->data zur Verfügung. In diesem Fall können die Schlüssel der jeweiligen Felder dazu verwendet werden, die eingegebenen Daten aus dem Array $this-> data auszulesen. 61

66 3 Basismodule für papaya CMS programmieren Die Methode getparseddata() überladen Die Methode getparseddata() wird aufgerufen, um den Inhalt des Moduls auszugeben. Durch Überladen der Methode bestimmen Sie den auszugebenden Inhalt: 1 <?php 2 Listing 3.8: Methode getparseddata() überladen 3 require_once(papaya_include_path. system/base_content.php ); 4 5 class content_example extends base_content { 6 7 $editfields = array( 8 title => array( Title, issometext, TRUE, input, 200,, ), 9 teaser => array( Teaser, issometext, FALSE, simplerichtext, 5,, ), 10 text => array( Text, issometext, FALSE, richtext, 15,, ) 11 ); function getparseddata() { 14 $this->setdefaultdata(); 15 $result = <example>.lf; 16 $result.= sprintf( <title>%s</title>.lf, 17 papaya_strings::escapehtmlchars($this->data[ title ])); 18 $result.= sprintf( <text>%s</text>.lf, 19 $this->getxhtmlstring($this->data[ text ])); 20 $result.= </example>.lf; 21 return $result; 22 } 23 } 24?> Die Inhaltsdaten für eine Seite werden vom Benutzer im Backend unter Inhalt bearbeiten eingegeben. Das Eingabeformular ist über die $editfields definiert. papaya CMS liest diese Daten automatisch aus der Datenbank aus und lädt diese in das assoziative Array $ this->data. Sie können auf die Daten zugreifen, indem Sie mit den Schlüsseln der Felder im Array $editfields das Array $this->data auslesen.! Standard-Daten in das Array this > dataladenthis->datawenn keine Daten eingegeben wurden, ist das Array $this->data leer. Der Versuch, mit den entsprechenden Schlüsseln auf die Feldwerte zuzugreifen, löst eine Notice aus. Um das zu verhindern, gehen Sie wie folgt vor:geben Sie für jedes Feld in den $editfields immer einen Standardwert ein. Rufen Sie in der Methode getparseddata() als erstes die Methode $this->setdefaultdata() auf. Damit wird das Array $this->data mit den Standardwerten gefüllt, die in den $editfields angegeben sind. Wenn Sie die Inhalte der Felder ausgeben, müssen diese maskiert werden. Dafür wird im Quellcode-Beispiel die Methode papaya_strings::escapehtmlchars() verwendet. Für den Haupttext wird die Methode base_object::getxhtmlstring() verwendet. Näheres dazu erfahren Sie in Abschnitt 3.3, S

67 3.1 Box- und Seitenmodule programmieren Die Methode getparsedteaser() ist ähnlich aufgebaut wie getparseddata(). Der Unterschied besteht darin, dass getparsedteaser() von speziellen Übersichtsseiten und bestimmten Boxen aufgerufen wird, um die Seite anzuteasern. Daher gibt diese Funktion immer einen Kurztext aus. Darüber hinaus ist diese Methode optional. Sie muss anders als getparseddata() nicht durch Seitenmodule implementiert werden, damit das Seitenmodul Inhalte ausgeben kann. 1 <?php 2 Listing 3.9: Methode getparsedteaser() überladen 3 require_once(papaya_include_path. system/base_content.php ); 4 5 class content_example extends base_content { 6 7 $editfields = array( 8 title => array( Title, issometext, TRUE, input, 200,, ), 9 teaser => array( Teaser, issometext, FALSE, simplerichtext, 5,, ), 10 text => array( Text, issometext, FALSE, richtext, 15,, ) 11 ); function getparseddata() { 14 $this->setdefaultdata(); 15 $result = <example>.lf; 16 $result.= sprintf( <title>%s</title>.lf, 17 papaya_strings::escapehtmlchars($this->data[ title ])); 18 $result.= sprintf( <text>%s</text>.lf, 19 $this->getxhtmlstring($this->data[ text ])); 20 $result.= </example>.lf; 21 return $result; 22 } function getparsedteaser() { 25 $this->setdefaultdata(); 26 $result = ; 27 $result.= sprintf( <title>%s</title>.lf, 28 papaya_strings::escapehtmlchars($this->data[ title ])); 29 $result.= sprintf( <teaser>%s</teaser>.lf, 30 $this->getxhtmlstring($this->data[ text ])); 31 return $result; 32 } 33 } 34?> Beim Seitenaufruf gibt die Methode getparsedteaser() selbst keine Daten aus. Die Funktion wird immer dann aufgerufen, wenn die Seite von Übersichtsseiten oder -boxen angeteasert wird. Eine Übersichtsseite ist beispielsweise eine Seite mit dem Modul Category with Image. Dieses Modul ruft die Methode getparsedteaser() aller unmittelbaren Unterseiten auf und stellt sie in einer verlinkten Übersicht dar. Als letzten Schritt tragen Sie das Seitenmodul wie in Abschnitt 3.4.3, S. 91 beschrieben in die modules.xml ein. Nachdem Sie in der Modulverwaltung den Modulscan durchgeführt haben, wird das neue Modul erkannt und kann verwendet werden. 63

68 3 Basismodule für papaya CMS programmieren Eingabemasken für Inhaltsmodule denieren Eingabemasken für Box- und Seitenmodule werden über ein assoziatives Array definiert. Die notwendige Funktionalität dazu erben die beiden Basisklassen base_actionbox und base_content von der gemeinsamen Elternklasse base_plugin. Um eigene Eingabefelder zu definieren, müssen Sie das Klassenattribut $editfields überladen. Die Ausgabe der Eingabemaske erledigt das System anschließend von selbst. Im folgenden Listing wird die Struktur des Arrays $editfields aufgeführt: 1 editfields [ 2 feldname => array[ 3 Feldtitel, 4 Testfunktion, 5 Pflichtfeld? (TRUE FALSE), 6 Feldtyp, 7 Feldparameter (hängt vom Typ ab), 8 Hilfstext, 9 Standardwert 10 ], 11 Zwischenüberschrift 12 ] Listing 3.10: Ausfüllschema für $editfields-array Die folgende Tabelle beschreibt die einzelnen Felder: Feld Feldtitel Testfunktion Pflichtfeld Feldtyp Feldparameter Hilfstext Tabelle 3.1: Bedeutung der einzelnen Felder Bedeutung Beschriftung des Feldes. Die Beschriftung wird in englischer Sprache eingegeben und durch das Phrasensystem von papaya CMS übersetzt. Der Plausibilitätscheck, mit dem die Nutzereingabe überprüft wird. TRUE, wenn dieses Feld ausgefüllt werden muss, andernfalls FALSE. Typ des Eingabefeldes, beispielsweise einzeilige oder mehrzeilige Textfelder, siehe Tabelle 3.2, S. 66. Je nach ausgewähltem Feldtyp können entsprechende Parameter eingefügt werden, siehe Tabelle 3.2, S. 66. Dieser Hilfstext wird als title-attribut im Glühbirnen-Icon dargestellt, das hinter die Feldbeschriftung gesetzt wird. 64

69 3.1 Box- und Seitenmodule programmieren Feld Standardwert Tabelle 3.1: Bedeutung der einzelnen Felder (forts.) Bedeutung Standardwert für dieses Feld. Die Standardwerte werden über die Methode $this->setdefaultdata() in das Array $this->data geladen und stehen im Content-Modul zur Verfügung. Ein konkretes Beispiel für ein ausgefülltes $editfield-array sehen Sie im folgenden Listing: Listing 3.11: Beispiel für $editfields 1 $editfields = array( 2 max => array( Count, isnum, TRUE, input, 5,, 100), 3 columns => array( Column count, isnum, TRUE, input, 1,, 2), 4 sort => array( Sort, isnum, TRUE, translatedcombo, 5 array(0 => Ascending, 1 => Descending, 2 => Random ),, 0), 6 Image, 7 image => array( Image, issometext, FALSE, image, 400,, ), 8 imgalign => array( Image align, isalpha, TRUE, combo, 9 array( left => left, right => right ),, left ), 10 breakstyle => array( Text float, isalpha, TRUE, combo, 11 array( none => None, side => Side, center => Center ),, none ), 12 ); Jedes einzelne Feld im $editfields-array besteht aus einem Schlüssel, das auf ein eingebettetes Array zeigt. Das eingebettete Array enthält die eigentliche Felddefinition. Neben diesen Schlüssel-Array-Paaren kann das Array auch einfache Strings enthalten. Die Strings werden in der Eingabemaske als Zwischenüberschriften dargestellt. Im obigen Listing stellt Image eine solche Zwischenüberschrift dar. Das Array aus dem obigen Listing würde ein Eingabeformular erzeugen, das folgendermaßen aussieht: 65

70 3 Basismodule für papaya CMS programmieren Abbildung 3.2: Eingabemaske des Seitenmoduls Category with image Feldtypen In der folgenden Tabelle sind alle Feldtypen und ihre Parameter aufgelistet: Tabelle 3.2: Feldtypen und ihre möglichen Parameter Feldtyp Beschreibung Parameter captcha Dynamisches Bild für Captcha auswählen. ID des dynamischen Bildes. checkbox Checkbox ausgeben Beschriftung der Checkbox. checkgroup combo Eine Gruppe von Checkboxen für die Mehrfachauswahl. Drop-Down-Liste mit verschiedenen Einträgen. Assoziatives Array, das den Titel sowie den Parameternamen der Checkboxen enthält, die als Gruppe zusammengefasst werden. Assoziatives Array mit den einzelnen Auswahloptionen. Die Auswahloptionen können gruppiert werden, indem das assoziative Array weitere eingebettete Arrays enthält. 66

71 3.1 Box- und Seitenmodule programmieren Tabelle 3.2: Feldtypen und ihre möglichen Parameter (forts.) Feldtyp Beschreibung Parameter color date dircombo Eingabefeld mit optionalem Farbauswahldialog. Eingabefeld mit optionalem Datumsauswahldialog. Drop-Down-Liste mit Verzeichnissen aus dem Dateisystem des Servers. Maximale Zeichenlänge der Eingabe. Der Parameterwert wird sowohl für das Attribut maxlength als auch für das Attribut size benutzt. Maximale Zeichenlänge der Eingabe. Der Parameterwert wird sowohl für das Attribut maxlength als auch für das Attribut size benutzt. Ein Array bestehend aus drei Elementen: Pfad zu einem Zielverzeichnis, ausgehend vom Basisverzeichnis. Basisverzeichnis (page, admin oder upload; oder ein absolutes Verzeichnis auf dem Dateisystem des Servers) Regulärer Ausdruck, der die Liste der anzuzeigenden Dateien beschränkt. file Dateiupload-Feld, identisch mit imagefile. Maximale Zeichenlänge der Eingabe. Der Parameterwert wird sowohl für das Attribut maxlength als auch für das Attribut size benutzt. 67

72 3 Basismodule für papaya CMS programmieren Tabelle 3.2: Feldtypen und ihre möglichen Parameter (forts.) Feldtyp Beschreibung Parameter filecombo Drop-Down-Liste mit Dateiauswahl. Array mit vier Feldern für folgende Daten: Pfad: Relativer Pfad ausgehend vom Basisverzeichnis im Dateisystem des Servers. Regulärer Ausdruck: Nur Dateien auflisten, auf die der reguläre Ausdruck trifft. TRUE, wenn in der Drop- Down-Liste auch ein leerer Eintrag für die Nullauswahl vorhanden sein soll, andernfalls FALSE (Standard) Basisverzeichnis (optional): Eines von folgenden Kürzeln theme (absoluter Pfad zum papaya-theme), page (absoluter Pfad zum Installationsverzeichnis innerhalb von DocumentRoot von papaya CMS), admin (wie page, nur innerhalb des Admin-Verzeichnisses von papaya CMS), upload (absoluter Pfad zum Uploadverzeichnis der MediaDB); standardmäßig wird eine Callback-Methode erwartet. function Das Feld wird durch eine Callback- Funktion bestimmt. Name einer Callback-Funktion, die beispielsweise die Auswahloptionen für Drop-Down-Listen zurückgibt. 68

73 3.1 Box- und Seitenmodule programmieren Tabelle 3.2: Feldtypen und ihre möglichen Parameter (forts.) Feldtyp Beschreibung Parameter geopos image Eingabefeld mit optionalem Dialog zur Auswahl von Geo-Positionsdaten über den Google Maps Api-Server. Eingabefeld mit optionalem Dialog zur Formatierung und Auswahl von Bilddateien aus der MediaDB. imagefile Dateiupload-Feld, identisch mit file. imagefixed info Eingabefeld mit optionalem Dialog, um Bilddateien direkt aus der MediaDB auszuwählen. Einfaches Textlabel zur Information ohne Bearbeitungsmöglichkeit. Wert für das size-attribut des Eingabefeldes. Wert für das size-attribut des Eingabefeldes. Maximale Zeichenlänge der Eingabe. Der Parameterwert wird sowohl für das Attribut maxlength als auch für das Attribut size benutzt. Wert für das size-attribut des Eingabefeldes. input Einzeiliges Texteingabefeld. Maximale Zeichenlänge der Eingabe. Der Parameterwert wird sowohl für das Attribut maxlength als auch für das Attribut size benutzt. mediafile mediafolder mediaimage pageid Eingabefeld mit optionalem Dialog, um eine Datei aus der MediaDB auswählen. Drop-Down-Liste mit allen Ordnern der MediaDB. Eingabefeld mit optionalem Dialog, über das ein Bild aus der MediaDB ausgewählt werden kann. Eingabefeld mit optionalem Dialog, um eine Seiten-ID auszuwählen. n/a Wert für das size-attribut des Eingabefeldes. n/a Assoziatives Array mit den Schlüsseln width und height, wodurch Breite und Höhe des angezeigten Bildes bestimmt werden. Maximale Zeichenlänge der Eingabe. Der Parameterwert wird sowohl für das Attribut maxlength als auch für das Attribut size benutzt. 69

74 3 Basismodule für papaya CMS programmieren Tabelle 3.2: Feldtypen und ihre möglichen Parameter (forts.) Feldtyp Beschreibung Parameter password Passwortfeld. Eingaben werden maskiert. Maximale Zeichenlänge der Eingabe. Der Parameterwert wird sowohl für das Attribut maxlength als auch für das Attribut size benutzt. radio Radiobutton Assoziatives Array mit dem Schlüssel als Buttonwert (value-attribut) und dem Array-Wert als Button- Beschriftung. richtext simplerichtext Mehrzeiliges Textfeld mit Richtext- Editor. Mehrzeiliges Textfeld mit einfachem Richtext-Editor Maximale Anzahl der Zeilen. Maximale Anzahl der Zeilen. textarea Mehrzeiliges Textfeld. Maximale Anzahl der Zeilen. translatedcombo yesno Drop-Down-Liste, dessen Einträge durch die Phrasenkomponente übersetzt werden. Zwei Radiobuttons für Ja-Nein- Auswahl. Assoziatives Array mit Schlüssel- Wert-Paaren. Der Schlüssel wird als Wert für das value-attribut des <option>-elements benutzt, der Wert als Beschriftungstext. Der Beschriftungstext wird durch das Phrasensystem von papaya CMS übersetzt. n/a 3.2 POST/GET-Parameter lesen und Sessiondaten verwalten papaya CMS speichert POST/GET-Parameter automatisch in einem Array ab, auf das Sie mit Ihrem Modul zugreifen können. Auch die Verwaltung von Sessiondaten wird weitestgehend über Methoden erleichtert, die das Basissystem von papaya CMS zur Verfügung stellt. Wie Sie auf POST/GET-Daten zugreifen, erfahren Sie in Abschnitt 3.2.1, S

75 3.2 POST/GET-Parameter lesen und Sessiondaten verwalten Wie Sie Daten in der Session speichern und wieder auslesen, erfahren Sie in Abschnitt 3.2.2, S Auf POST/GET-Daten zugreifen Jede dynamische Webanwendung lebt davon, dass sie auf Benutzereingaben in Form von Formularen und parametrisierten Links reagieren kann. Damit unterschiedliche Anwendungen sich dabei nicht ins Gehege kommen, verwendet jedes Modul in papaya CMS einen anderen Identifier, den so genannten $paramname. papaya CMS verwendet diesen, um Links und Formularfelder entsprechend zu benennen. Die HTML-Ausgabe sieht folgendermaßen aus: Listing 3.12: Identifier für Parameternamen 1 <form action="mymodule.123.html?my[mode]=test" method="post"> 2 <input type="text" name="my[name]" /> 3 </form> Die Methode base_object::initializeparams() lädt alle für die Anwendung relevanten Parameter in die Instanzvariable $this->params. $this->params hat den Typ Array. Damit die Methode initializeparams() ausschließlich diejenigen Daten in das Array $this->params lädt, die auch zur Anwendung gehören, müssen Sie dem Attribut $paramname einen eindeutigen Parameternamen zuweisen. Dieser Parametername sollte sofort kennzeichnen, zu welcher Anwendung die jeweiligen Parameter gehören. So könnte der $paramname für die Anwendung Meine tolle Anwendung beispielsweise mta lauten. Wenn Sie also ein Seiten- oder Boxmodul geschrieben haben, das Nutzerdaten entgegennimmt, müssen Sie auf jeden Fall base_object::initializeparams() in Ihrer Klasse ausführen. Erst dann können Sie auf diese Daten über $this->params zugreifen. Die geeignete Stelle dafür in Seiten- und Boxmodulen ist die Methode getparseddata(). Im folgenden Codebeispiel wird dargestellt, wie base_object::initializeparams( ) in einem Seitenmodul benutzt wird: var $paramname = my ; 3 Listing 3.13: base_object::initializeparams() aufrufen 4 function getparseddata() { 5 $this->initializeparams(); 6 //... 7 }

76 3 Basismodule für papaya CMS programmieren Anschließend stehen die übermittelten Parameter in $this->params zur Verfügung. Ausgehend vom o.g. Formularbeispiel enthält $this->params beispielsweise folgende Inhalte: 1 array( 2 mode => test, 3 name => Friedrich, 4 ); Listing 3.14: Beispielinhalte des Arrays $this->params Wenn POST- und GET-Parameter eingelesen werden, sind folgende Punkte zu beachten: Wird ein POST-Parameter mit dem selben Namen wie ein GET-Parameter übertragen, wird der GET-Parameter überschrieben. POST-Parameter haben also in der Auswertung stets Vorrang vor gleichnamigen GET-Parametern. Die Methode initializeparams() kümmert sich auch um Magic Quotes, also das Maskieren der Daten. Strings werden automatisch nach UTF-8 umgewandelt. Wenn Sie die getlink()-ähnlichen Methoden verwenden um Links zu generieren, müssen Sie nicht manuell die GET-Parameter abhängig von $paramname zusammensetzen. Es genügt, wenn Sie den Methoden den Parameternamen sowie die Liste der Parameter und Werte in Form eines assoziativen Arrays übergeben. Näheres zu den Link-Methoden erfahren Sie in Abschnitt 3.3.4, S. 82. Auch base_dialog sowie base_frontend_form kümmert sich automatisch um die korrekte Ausgabe der Parameter, siehe Abschnitt 3.3.5, S Daten in der Session speichern papaya CMS enthält eine umfangreiche Logik, um die Session zu verwenden. Verschiedene mögliche PHP-Konfigurationen werden dabei berücksichtigt und unterschiedliche Session-Modi unterstützt. Dieser Abschnitt beschränkt sich auf die Benutzung der Session in papaya CMS. Zumeist kommt die Session zum Einsatz, wenn der Zustand einer Anwendung nicht über eine elend lange Liste von GET-Parametern nachverfolgt werden soll oder kann. Optionen, die ein Nutzer gewählt hat, können in der Session abgelegt werden und stehen damit beim nächsten Seitenaufruf wieder zur Verfügung. Es gibt drei Möglichkeiten die Session zu verwenden: 72

77 3.2 POST/GET-Parameter lesen und Sessiondaten verwalten Parameter persistent machen und bei Bedarf automatisch zurücksetzen, siehe Abschnitt 3.2.3, S. 73. Daten in der Session frei speichern, siehe Abschnitt 3.2.4, S. 75. Sesisonspeicherklasse für umfangreiche Daten einsetzen, siehe Abschnitt 3.2.5, S Parameterwerte persistent machen und automatisch zurücksetzen Sie können papaya CMS anweisen, Parameter automatisch in der Session vorzuhalten. Damit werden die Parameter solange beibehalten, bis ein bestimmter anderer Parameter übermittelt wurde oder sie von Ihnen zurückgesetzt werden. Anhand der Beispielanwendung Stickers aus Kapitel 4, S. 101 soll die Funktionsweise der Sessiondatenverwaltung in papaya CMS vorgestellt werden. Die Stickers -Anwendung verwaltet verschiedene Zitate, die nach Sammlungen geordnet werden können. Die Anwendung erlaubt es also, dass Sie verschiedene Sammlungen hinzufügen und verwalten können, wobei jede Sammlung beliebig viele Einträge enthalten darf. Wenn Sie in der Stickers -Anwendung gerade einen Eintrag bearbeiten, soll der aktuell ausgewählte Eintrag in der Liste der Einträge markiert bleiben, auch wenn Sie gerade auf den Speichern-Button geklickt haben. Während Sie also den Eintrag bearbeiten, darf diese Information nicht verloren gehen. Sie wollen jedoch nicht jedesmal die ID des Eintrags (sticker_id) übermitteln. Indem Sie den Parameter sticker_id mittels base_object: :initializesessionparam() registrieren, wird dieser in der Session vorgehalten. Beim nächsten Seitenaufruf prüft die Methode initializeparams(), ob ein Parameter registriert ist und nicht erneut übermittelt wurde. Dann wird der Wert aus der Session geladen. Im Folgenden soll Schrittweise erklärt werden, wie Sie den Status eines Formulars in der Session speichern: 1. Definieren Sie zunächst den Parameternamen für die Session. Speichern Sie diesen in der Instanzvariablen $this->sessionparamname ab. Verknüpfen Sie den Session-Parameternamen mit dem Parameternamen aus der Instanzvariablen $this->paramname, um Konflikte mit anderen Klassen zu vermeiden: Listing 3.15: Parameternamen für die Session speichern function getparseddata() { 3 $this->sessionparamname = PAPAYA_SESS_.$this->paramName; 4 }

78 3 Basismodule für papaya CMS programmieren 2. Initialisieren Sie die Parameter mit base_object::initializeparams() und laden Sie die Sessiondaten mit base_object::getsessionvalue() in das Attribut $sessionparams: Listing 3.16: Sessionparameter initialisieren und Sessiondaten laden function getparseddata() { 3 $this->sessionparamname = PAPAYA_SESS_.$this->paramName; 4 $this->initializeparams(); 5 $this->sessionparams = $this->getsessionvalue($this->sessionparamname); 6 } Nach der Initialisierung der einzelnen Sessionparameter müssen die geänderten Sessiondaten mittels base_object::setsessionvalue() gespeichert werden: Listing 3.17: Sessionparameter initialisieren und geänderte Sessiondaten speichern function getparseddata() { 3 $this->sessionparamname = PAPAYA_SESS_.$this->paramName; 4 $this->initializeparams(); 5 $this->sessionparams = $this->getsessionvalue($this->sessionparamname); 6 7 //Einzelne Sessionparameter initialisieren 8 $this->initializesessionparams( sticker_id ); 9 $this->initializesessionparams( col_id, array( sticker_id )); //Sessiondaten speichern 12 $this->setsessionvalue($this->sessionparamname, $this->sessionparams); 13 } In diesem Beispiel enthält der zweite Aufruf von initializesessionparams() als zweiten Parameter ein Array mit dem Wert sticker_id. Dieser zweite Parameter enthält die IDs aller Sessiondaten, die entfernt werden sollen, wenn der erste Parameter in POST oder GET enthalten ist. Im obigen Beispiel wird also der Wert des Sessioneintrags sticker_id entfernt, wenn sich der Wert des Eintrags für col_id (die ID der Collection/Sammlung) geändert hat. Die ID des Stickers wird entfernt, um die Datenkonsistenz zu gewährleisten. Wenn der Nutzer eine andere Collection auswählt, soll die ID des zuvor ausgewählten Stickers nicht gespeichert bleiben, da der Sticker zu einer anderen Collection gehört. 74

79 3.2 POST/GET-Parameter lesen und Sessiondaten verwalten! Wenn Sie Daten-IDs wie im obigen Beispiel die ID des Stickers oder der Collection in der Session speichern, müssen Sie die IDs nicht immer wieder als Parameter übermitteln oder sie manuell in der Session ablegen. Achten Sie aber darauf, IDs von Elementen beim Bearbeiten oder Löschen immer explizit als Formularparameter anzugeben. Andernfalls kann es zu ungewünschten Seiteneffekten kommen, wenn der Nutzer mit mehreren Browsertabs oder -fenstern arbeitet. Versehentlichen Datenverlust verhindernwenn beispielsweise ein Benutzer die Collection mit der ID 2 zum Bearbeiten auswählt, wird die Collection-ID mit dem Wert 2 in der Session abgelegt. In einem zweiten Tab wählt er die Collection mit der ID 5 aus. Die ID 5 wird in der Session abgelegt, überschreibt dabei jedoch die vorherige Collection-ID. Speichert der Benutzer jetzt im ersten Browsertab den Datensatz, wird der ID-Wert aus der Session genommen und Sammlung 5 mit den Änderungen überschrieben. Dieser Fall kann nicht eintreten, wenn das Formular die ID der Collection explizit übermittelt Daten frei in der Session speichern Bei umfangreichen Anwendungen ist der soeben beschriebene Ansatz mit Parametern nicht günstig. Komplexe Anwendungen können verschiedene Seiten- und Boxmodule besitzen, die Informationen miteinander teilen. Jedes Modul der Anwendung muss die Parameternamen kennen und die Parameter initialisieren, was schnell unübersichtlich werden würde. Es kann daher sinnvoll sein, Daten explizit in der Session abzulegen. Um Konflikte zu verhindern und den Zugriff auf $_SESSION zu abstrahieren, stellt base_object zwei Funktionen zur Verfügung: base_object::setsessionvalue() und base_ object::getsessionvalue(). Im folgenden Beispiel wird eine Session-Speicherklasse vorgestellt, die drei Methoden implementiert: function initialize() {} 3 function setuserloggedin($userid) {} 4 function getuserloggedin($userid) {} 5... Listing 3.18: Beispiel einer Session-Speicherklasse Methode zum Initialisieren der Sessiondaten Die Methode initialize() liest die Session-Daten beim Initialisieren der Klasse in die lokale Variable $this->sessionparams. Bei einem Zugriff auf die Session-Daten müs- 75

80 3 Basismodule für papaya CMS programmieren sen also nicht jedes Mal die kompletten Session-Daten ausgelesen werden. Die Daten stehen anderen Methoden für die gesamte Lebenzeit der Klasse im Attribut $this->sessionparams zur Verfügung: Listing 3.19: Sessionparameternamen für Klasse initialisieren function initialize() { 3 $this->_sessionparamname = get_class(). _user_options ; 4 $this->sessionparams = $this->getsessionvalue($this->_sessionparamname); 5 } 6... Damit es keine Überschneidungen gibt, können Sie $sessionparamname aus dem Klassennamen und einem Identifier zusammensetzen. Methode für den Schreibzugri auf Sessiondaten Die Methode setuserloggedin() schreibt die modifizierten Session-Daten zuerst in das lokale array $this->sessionparams. Anschließend werden die Sessiondaten mit der Methode $this->setsessionvalue() in die Session geschrieben: Listing 3.20: Wert in der Session ändern function setuserloggedin($userid) { 3 $this->sessionparams[ logged_in ] = 1; 4 $this->setsessionvalue($this->_sessionparamname, $this->sessionparams); 5 } 6... Methode für den Lesezugri auf Sessiondaten Die Methode getuserloggedin() überprüft, ob der gesuchte Wert in der lokalen Variablen $this->sessionparams enthalten ist. Ist dies der Fall, können Sie ihn mit return an die aufrufende Instanz zurückgeben: Listing 3.21: Wert aus der Session auslesen function getuserloggedin($userid) { 3 if (isset($this->sessionparams[ logged_in ])) { 4 return $this->sessionparams[ logged_in ]; 5 } 6 }

81 3.2 POST/GET-Parameter lesen und Sessiondaten verwalten Die Methode benutzt also nicht $this->getsessionvalue(), um die Sessiondaten zuerst in ein lokales Array zu lesen, sondern greift auf die Daten im Klassenattribut $this- >sessionparams zu Separate Klasse als Session-Speicher verwenden Für sehr umfangreiche Anwendungen bietet es sich an, Sessiondaten in einem separaten Objekt zu verwalten. Sie können mit Hilfe eines Singletons und statischen Methoden eine schlanke, leicht zu nutzende Klasse schreiben: 1 <?php 2 Listing 3.22: Beispiel einer Sessionspeicherklasse 3 require_once(papaya_include_path. system/sys_base_object.php ); 4 5 class my_app_options extends base_object { 6 7 var $_sessionparamname = ; 8 9 function &_getinstance() { 10 static $instance; 11 if (!isset($instance) 12!is_object ($instance) 13!is_a($instance, my_app_options ) { 14 $instance = new my_app_options; 15 $instance->initialize(); 16 } 17 return $instance; 18 } function initialize() { 21 $this->_sessionparamname = get_class(). _app_options ; 22 $this->sessionparams = $this->getsessionvalue($this->_sessionparamname); 23 } function savesession() { 26 return $this->setsessionvalue($this->_sessionparamname, $this->sessionparams); 27 } function setoptionexamplevalue($value = ) { 30 $optionobj = self::_getinstance(); 31 $optionobj->sessionparams[ example_value ] = $value; 32 return $this->savesession(); 33 } function getoptionexamplevalue() { 36 $optionobj = self::_getinstance(); 37 if (isset($optionobj->sessionparams[ example_value ])) { 38 return $optionobj->sessionparams[ example_value ]; 39 } 40 } 41 } 42?> Verwendet werden kann die Sessionspeicherklasse my_app_options folgendermaßen: 77

82 3 Basismodule für papaya CMS programmieren Listing 3.23: Sessionspeicherklasse benutzen my_app_options::setoptionexamplevalue( test ); 3 $value = my_app_options::getoptionexamplevalue(); Content ausgeben und Nutzereingaben maskieren Inhalte werden in papaya CMS entweder als Klartext oder im XML-Format in der Datenbank gespeichert. Wenn bestimmte Inhalte von Seiten oder Boxen als XML ausgegeben werden, müssen diese Inhalte entsprechend maskiert werden, damit kein ungültiges XML- Dokument ausgegeben wird. Ungültiges XML kann nämlich durch den Ausgabefilter nicht mehr wie vorgesehen in das Zielformat umgewandelt werden. Aber nicht nur bei der Ausgabe von Inhalten muss gegebenenfalls maskiert werden, sondern auch bei Inhalten, die durch Nutzereingaben in das System gelangen. Zu diesen klassischen Nutzereingaben zählen zum Beispiel Daten aus Kontaktformularen, Kommentarboxen, Foreneinträge oder Gästebüchern.! papaya CMS liest Parameterdaten aus den POST- und GET-Array in das Array $this- >params ein. Dabei werden die Daten maskiert. Sie müssen also keine Maskierung vornehmen, wenn Sie auf die Daten im params-array zugreifen. Wenn Sie jedoch auf das Array $_POST oder $_GET zugreifen, müssen Sie sich selbst um die Maskierung kümmern Text bei der Ausgabe maskieren In der Klasse base_object ist die Methode getxhtmlstring() implementiert, mit der Sie ein gültiges XHTML-Dokument ausgeben können. Diese Methode sorgt dafür, dass auf jeden Fall ein gültiges XML-Dokument ausgegeben wird, indem bestimmte Sonderzeichen wie & oder ä in entsprechende HTML-Entitys umgewandelt werden. Tags bleiben jedoch erhalten, ebenso wie bereits definierte Entities. Wird der Funktion als zweiten Parameter TRUE übergeben, werden alle im String enthaltenen Zeilenumbrüche in <br />-Elemente umgewandelt. Das folgende Beispiel zeigt, wie die Methode aufgerufen werden kann: 78

83 3.3 Content ausgeben und Nutzereingaben maskieren Listing 3.24: Codebeispiel für base_object::getxhtmlstring() function getparseddata() { $result.= sprintf( 5 <teaser>%s</teaser>.lf, 6 $this->getxhtmlstring($this->data[ teaser ],!(bool)$this->data[ nl2br ]) 7 ); } Im obigen Beispiel wird getxhtmlstring() in der Funktion getparseddata() benutzt, um einen String zu maskieren, der in ein XML-Element eingefügt werden soll. Die Methode getxhtmlstring() garantiert, dass der einzufügende String auf jeden Fall gültiges XHTML ist. Zu diesem Zweck führt getxhtmlstring() intern eine Überprüfung durch, indem der String mit der Klasse simple_xmltree getestet wird. Falls dieser Test fehlschlägt, wird der komplette String maskiert, indem die Methode escapehtmlchars( ) aus der Klasse papaya_strings auf den String angewendet wird. Wann Sie getxhtmlstring() und wann escapehtmlchars() benutzen sollten Wenn eine Benutzereingabe HTML-Zeichen enthalten darf, müssen Sie die Methode base_ object::getxhtmlstring() anwenden. Diese Methode erstellt gültiges XML und erhält gleichzeitig die enthaltenen HTML-Tags. Ist für die Benutzereingabe HTML nicht vorgesehen, müssen Sie papaya_strings:: escapehtmlchars() verwenden. Dadurch stellen Sie sicher, dass alle HTML-Sonderzeichen maskiert werden. Welche Ausgabemethode für die Maskierung benutzen, hängt auch von den eingesetzten Plausibilitätschecks ab. Wenn Sie Eingabeformulare über $editfields oder mit base_ dialog erzeugen, wählen Sie für jedes Feld auch einen Plausibilitätscheck aus. Diese Überprüfungsmethoden aus der Klasse checkit bestimmen mehr oder weniger restriktiv, welche Werte in Felder eingegeben werden dürfen. Ist als Prüffunktion issometext angegeben, sollten Sie base_object::getxhtmlstring() für die Ausgabemaskierung benutzen. Ist als Prüffunktion isnohtml oder restriktiver (isnum, isalpha und dergleichen) angegeben, reicht papaya_strings::escapehtmlchars(). Letzteres ist performanter, da das XML nicht validiert werden muss. 79

84 3 Basismodule für papaya CMS programmieren Nutzereingaben maskieren Nutzereingaben sollten maskiert werden, um diverse Sicherheitslücken wie beispielsweise SQL-Injection-Lücken sowie Cross-Site-Scripting-Lücken zu verhindert. Eine SQL-Injection bezeichnet das Einschleusen von Datenbankbefehlen durch einen Angreifer, um beispielsweise Daten zu löschen, zu stehlen oder zu manipulieren. Bei einer Cross-Site-Scripting-Attacke werden Nutzereingaben unkontrolliert in einer Webseite ausgegeben. Dies ist zum Beispiel bei Weblogs möglich, in denen Nutzereingaben als Kommentar zum Blogeintrag dargestellt werden. Wird die Eingabe nicht maskiert, kann ein Angreifer beispielsweise Schadcode in Form von bestimmten JavaScript-Programmen in die Seite einschleusen, der in Browsern von Besuchern ausgeführt wird. Nutzerdaten werden in der Regel automatisch durch Methoden wie initializeparams( ) maskiert. Näheres dazu erfahren Sie in Abschnitt 3.2, S. 70. Sie können jedoch auch bei der Ausgabe der Daten dafür sorgen, dass fremde Nutzereingaben maskiert ausgegeben werden, siehe Abschnitt 3.3.1, S Strings für Datenbankabfrage maskieren Strings werden automatisch durch Methoden der Datenbankabstraktion maskiert, bevor eine SQL-Abfrage stattfindet. In manchen Fällen sind Sie jedoch selber dafür verantwortlich, Nutzereingaben zu maskieren. Wenn Sie base_db::databasequeryfmt() verwenden, werden Parameter automatisch maskiert, die über die vprintf()-ähnliche Funktionsweise übergeben werden und nicht direkt im $sql stehen. Sie müssen weiterhin auf korrekte SQL-Syntax achten und prüfen, ob Werte für Bedingungen leer sind. Sie müssen aber Anführungszeichen und dergleichen nicht maskieren. Listing 3.25: Codebeispiel für eine einfache Datenbankabfrage 1 $sql = "SELECT my_id, my_title, my_description 2 FROM %s 3 WHERE my_title = %s 4 "; 5 $params = array($this->tablemyitems, $mytitle); 6 if ($res = $this->databasequeryfmt($sql, $params)) { 7 $result = $res->fetchrow(db_fetchmode_assoc); 8 } Wenn Sie komplexere Bedingungen wie IN () verwenden möchten, verwenden Sie die Methode base_db::databasegetsqlcondition( field_name, $values). Mit dieser Methode erhalten Sie eine gültige, maskierte SQL-Bedingung. Eine vollständige 80

85 3.3 Content ausgeben und Nutzereingaben maskieren Erklärung der Funktionsweise von base_db::databasegetsqlcondition() finden Sie in der Quellcodedokumentation. Das folgenden Listing stellt eine beispielhafte Anwendung der Methode databasegetsql- Condition() vor: Listing 3.26: Codebeispiel für base_db::databasegetsqlcondition() 1 $titlelist = array( one item, "joe s item", best item ); 2 3 $mycondition = $this->databasegetsqlcondition( my_title, $titlelist); 4 5 $sql = "SELECT my_id, my_title, my_description 6 FROM %s 7 WHERE $mycondition 8 "; 9 $params = array($this->tablemyitems); 10 //... Die SQL Abfrage sieht dann wie folgt aus: Listing 3.27: Beispielausgabe einer SQL-Abfrage mit maskierten Werten 1 SELECT my_id, my_title, my_description 2 FROM papaya_my_items 3 WHERE my_title IN ( one item, joe\ s item, best item );! Die die zugrunde liegende Implementierung der Methode databasegetsqlcondition() überprüft, ob der zweite Parameter mit dem Werte-Array gesetzt ist. Wenn der $values-parameter NULL ist, gibt die Methode den String 1 = 1 zurück. Wenn das $values-array hingegen leer ist, erhalten Sie den String 1 = 0. Die SQL-Query geht also keinesfalls kaputt, wenn das Array unerwartet NULL oder einfach nur leer sein sollte. Datensätze in die Datenbank einfügen Wenn Sie Datensätze mit base_db::databaseinsertrecords() einfügen oder mit base_db::databaseupdaterecord() ändern, brauchen Sie sich um das Maskieren ebenfalls keine Gedanken zu machen. Listing 3.28: Automatisches Maskieren bei databaseinsertrecord() 1 $data = array( 2 my_title => item 4, 3 my_description => "The best item ever", 4 ); 5 $this->databaseinsertrecord($this->tablemyitems, NULL, $data); 81

86 3 Basismodule für papaya CMS programmieren Wenn Sie komplexe SQL-Abfragen selbst zusammensetzen möchten und es mit den Bordmitteln nicht möglich ist die Abfrage zu erstellen, müssen Sie Zeichenketten gegebenenfalls selber maskieren. Verwenden Sie in solch einem Fall die Methode base_db::escapestr( ) um DBMS-abhängig die korrekte Maskierung zu erhalten Links ausgeben papaya CMS stellt einige Methoden zur Verfügung, mit denen Sie Links ausgeben können. Die Links berücksichtigen dabei den Kontext der Anwendung und die Konfiguration von papaya CMS. Diese Methoden sind alle in der Klasse base_object definiert und können somit in allen von base_object abgeleiteten Klassen über $this aufgerufen werden: Methode getlink() getweblink() getabsoluteurl() getwebmedialink() Tabelle 3.3: Linkausgabemethoden und ihre Verwendung Verwendung Mit dieser Methode erstellen Sie Links im Backend von papaya CMS, siehe Abschnitt 3.3.4, S. 82. Mit dieser Methode erstellen Sie Links für die Frontend- Ausgabe von papaya CMS, siehe Abschnitt 3.3.4, S. 83. Mit dieser Methode erhalten Sie eine absolute URL inklusive Protokoll und Domainnamen, siehe Abschnitt 3.3.4, S. 84. Mit dieser Methode erzeugen Sie eine absolute URL auf eine Datei aus der MediaDB, siehe?????, S.??. In den folgenden Abschnitten werden die Methoden kurz vorgestellt. Die Methode base_object::getlink() Verwenden Sie base_object::getlink() um Links für Anwendungen im Backend zu erstellen. Alle Parameter sind optional. 82

87 3.3 Content ausgeben und Nutzereingaben maskieren Parameter $params $paramname Tabelle 3.4: Parameter der Methode base_object::getlink() Beschreibung Die zu übergebenden Parameter, z.b. array( key => value, key2 => othervalue ). Erstellt abhängig vom $paramname (der Klasse oder der explizit übergebene) die GET-Parameter. Der zu verwendende Parametername. Nur anzugeben, wenn er vom Standard-Parameternamen im Klassenattribut $paramname abweicht, das im aktuellen Objekt gesetzt ist. $filename Name des auszuführenden PHP-Scriptes unterhalb von /papaya. Für Anwendungen ist das automatisch modules.php $pageid Eine Seiten-ID, sofern auf eine andere Seite verwiesen werden soll. Die Methode base_object::getweblink() Verwenden Sie base_object::getweblink() um einen Link für die Ausgabe im Frontend zu erstellen. Alle Parameter sind optional. Parameter $pageid $lng $mode Tabelle 3.5: Parameter der Methode base_object::getweblink() Beschreibung Die ID der Seite, die aufgerufen werden soll. Standard ist die aktuelle Seiten-ID. Die Sprache, in der die Seite aufgerufen werden soll. Entspricht dem lng_ident, z.b. de, en,... Modus, nicht der Ausgabemodus (html, pdf,...), sondern ob Vorschau preview, XML-Vorschau (xmlpreview) oder normal ( page, default). $params Parameter für diesen Link, array( key => value,...) $paramname $text Der Parametername, falls abweichend von $this- >paramname Der sprechende Name der URL, standardmäßig der normalisierte Seitentitel oder index. 83

88 3 Basismodule für papaya CMS programmieren Tabelle 3.5: Parameter der Methode base_object::getweblink() (forts.) Parameter $categid Beschreibung Kategorie-ID. Die numerische ID kann sich auf eine Kategorie aus dem Katalog beziehen, wenn die Seite der Kategorie zugeordnet worden ist. Die ID kann sich jedoch auch auf jede andere Ressource beziehen, die mit dem Seitenrequest angefordert wird. Die Methode base_object::getabsoluteurl() Verwenden Sie base_object::getabsoluteurl() um eine absolute URL zu erhalten. Die URL enthält das Protokoll und den Domainnamen. Die Methode sorgt dafür, dass die Session bei Bedarf nicht berücksichtigt wird. Bestandteile wie /../ werden aufgelöst und Parameter sowie Targets (#top) berücksichtigt. Tabelle 3.6: Parameter der Methode base_object::getabsoluteurl() Parameter $url $text $includesession Beschreibung Relative oder absolute URL oder Seiten-ID. Der sprechende Name der URL, standardmäßig der normalisierte Seitentitel oder index. TRUE, wenn die Session-ID in die URL übernommen werden soll, andernfalls FALSE. Die Methode base_object::getwebmedialink() Verwenden Sie base_object::getwebmedialink() um anhand einer Media-ID einen vollständigen Link auf eine Datei zu erhalten. Die Methode gibt einen Dateinamen zurück, z.b. dateiname.media abcdef abcdef.png Tabelle 3.7: Parameter der Methode base_object::getwebmedialink() Parameter Beschreibung $mediaid 32-stellige hexadezimale ID der Datei 84

89 3.3 Content ausgeben und Nutzereingaben maskieren Tabelle 3.7: Parameter der Methode base_object::getwebmedialink() (forts.) Parameter Beschreibung $mode Ausgabemodus: media, download, popup oder thumb: media: Für die MediaDB-ID wird ein einfacher Link zur Datei zurückgegeben. download: Dieser Modus wird so umgesetzt,dass entsprechende HTTP-Header gesetzt werden, damit der Browser den Datei-Speichern-Dialog darstellt. popup: Die Datei wird in einem JavaScript-Popup- Fenster geöffnet. Bilder können damit in der Vollbildansicht dargestellt werden. thumb: Die MediaDB-ID wird als Thumbnail-Link inklusive Größenangaben und Parametern interpretiert. $text $ext Der sprechende Name der URL, standardmäßig der normalisierte Dateiname oder index. Endung der Datei, z.b. png Formulare für die Seitenausgabe ausgeben Wenn Sie Formulare für die Seitenausgabe erzeugen wollen, können Sie das dazu erforderliche XML natürlich selbst im Content-Modul schreiben. Sie können sich jedoch viel Arbeit ersparen, wenn Sie das Formular-Toolkit verwenden, das in papaya CMS integriert ist. Dadurch erhalten alle erzeugten Formulare eine standardisierte Struktur, die dann später im Template einfacher in das Zielformat transformiert werden kann. Das Formular-Toolkit ist in der Klasse base_dialog implementiert. base_dialog benutzen Das folgende Listing zeigt, wie Sie ein Formular mit der Klasse base_dialog anlegen können: 85

90 3 Basismodule für papaya CMS programmieren 1. Definieren Sie zunächst ein Array, in dem Dialogfelder definiert werden: Listing 3.29: Dialogfelder definieren 1 function getdialogxml() { 2 $fields = array( 3 user_name => array( Name, isnohtml, TRUE, 4 input, 200,, Name ), 5 user_ => array( , isnohtml, TRUE, 6 input, 200,, username@domain.tld, left ), 7 subject => array( Betreff, isnohtml, TRUE, 8 input, 200,, Betreff ), 9 message => array( Nachricht, issometext, TRUE 10 textarea, 5,, Deine Nachricht ) 11 ); 12 } Näheres zur Definition von Dialogformularen erfahren Sie in Abschnitt 3.1.4, S Definieren Sie ein Array mit Standarddaten. Achten Sie darauf, dass die Schlüssel der jeweiligen Datenfelder mit den entsprechenden Schlüsseln im Dialogfeld-Array identisch sind: Listing 3.30: Array mit Standarddaten definieren 1 function getdialogxml() { 2 //Ausgeschnitten: $fields-array 3 $data = ( 4 //entspricht $field[ user_name ] 5 user_name => Name, 6 //entspricht $field[ user_mail ] 7 user_ => example@domain.tld, 8 //entspricht $field[ subject ] 9 subject => Betreff, 10 //entspricht $field[ message ] 11 message => Ihre Nachricht 12 ); 13 } 3. Optional können Sie ein Array für versteckte Parameterfelder definieren: Listing 3.31: Array mit versteckten Parameterfeldern definieren 1 function getdialogxml() { 2 //Ausgeschnitten: $fields-array 3 //Ausgeschnitten: $data-array 4 $hidden = array( 5 user_id => $userid, 6 submit => 1 7 ); 8 } 4. Legen Sie eine Instanz der Klasse base_dialog an: 1 function getdialogxml() { 2 //Ausgeschnitten: $fields-array 3 //Ausgeschnitten: $data-array 4 //Ausgeschnitten: $hidden-array 5 6 $this->dialog = &new base_dialog( 7 $this, $this->paramname, $fields, Listing 3.32: Klasse base_dialog instantiieren 86

91 3.3 Content ausgeben und Nutzereingaben maskieren 8 $data, $hidden 9 ); 10 } 5. Laden Sie die Formularfelder mit den Daten, die der Nutzer zuvor eingegeben hat. Diese liegen immer dann vor, wenn der Nutzer das Formular abgesendet hat, einige Eingaben jedoch fehlerhaft waren: Listing 3.33: Daten von Nutezrn in Formularfelder laden 1 function getdialogxml() { 2 //Ausgeschnitten: $fields-array 3 //Ausgeschnitten: $data-array 4 //Ausgeschnitten: $hidden-array 5 6 $this->dialog = &new base_dialog( 7 $this, $this->paramname, $fields, 8 $data, $hidden 9 ); 10 $this->dialog->loadparams(); 11 } 6. Geben Sie den Titel für den Dialog und den Absende-Button an: 1 function getdialogxml() { 2 //Ausgeschnitten: $fields-array 3 //Ausgeschnitten: $data-array 4 //Ausgeschnitten: $hidden-array 5 Listing 3.34: Titel für Button und Dialog eingeben 6 $this->dialog = &new base_dialog( 7 $this, $this->paramname, $fields, 8 $data, $hidden 9 ); 10 $this->dialog->loadparams(); 11 $this->dialog->dialogtitle = Kontaktformular ; 12 $this->dialog->buttontitle = Absenden ; 13 } 7. Geben Sie das XML des Dialogs aus: 1 function getdialogxml() { 2 //Ausgeschnitten: $fields-array 3 //Ausgeschnitten: $data-array 4 //Ausgeschnitten: $hidden-array 5 Listing 3.35: XML des Dialogs ausgeben 6 $this->dialog = &new base_dialog( 7 $this, $this->paramname, 8 $fields, $data, $hidden); 9 $this->dialog->loadparams(); 10 $this->dialog->dialogtitle = Kontaktformular ; 11 $this->dialog->buttontitle = Absenden ; 12 return $this->dialog->getdialogxml(); 13 } 87

92 3 Basismodule für papaya CMS programmieren 3.4 Verzeichnisse und Metadaten für Pakete erstellen Bevor Sie ein Modul für papaya CMS entwickeln können, müssen Sie erst ein Verzeichnis mit allen notwendigen Metadaten anlegen. Zu den Metadaten gehört die modules.xml. In dieser XML-Datei werden alle Module des Pakets aufgeführt. Des weiteren enthält das Paketverzeichnis ein Unterverzeichnis mit Tabellenstrukturbeschreibungen sowie ein Verzeichnis, das Grafiken für Admin-Module oder Buttons enthält. In diesem Abschnitt erfahren Sie folgendes: Wie Sie eine Verzeichnisstruktur für Pakete erstellen, siehe Abschnitt 3.4.2, S. 89. Wie Sie die Datei modules.xml schreiben, siehe Abschnitt 3.4.3, S. 91. Wie Sie Icons für das Admin-Modul definieren, siehe Abschnitt 3.4.4, S. 95. Wie Sie Tabellenstrukturdateien für bestehende Tabellen mit papaya CMS erstellen, siehe Abschnitt 3.4.5, S. 96. Wie Sie die Tabellenstrukturdateien in der modules.xml referenzieren, siehe Abschnitt 3.4.6, S. 97. Wie Sie die Anwendung als Paket ausliefern, siehe Abschnitt 3.4.7, S Wie Module in das System integriert werden Die Integration der Module in papaya CMS hängt maßgeblich vom Modultyp ab. Zunächst einmal werden alle Module in der Datenbanktabelle papaya_modules sowie papaya_ modulegroups registriert. Dazu wird die modules.xml des Pakets beim Modulscan eingelesen. Die Tabelle papaya_modulegroups entspricht einem Paket und enthält folgende Informationen: Die ID des Pakets. Den Namen des Pakets. Den Dateisystempfad zu den Modulen. Die Liste der Datenbanktabellen, die das Paket benutzt. In der Tabelle papaya_modules werden für jedes Modul die Angaben gespeichert, die in den Attributen des jeweiligen <module>-elements in der modules.xml angegeben sind, siehe Tabelle 3.10, S. 93. Weitere zusätzliche Informationen sind: 88

93 3.4 Verzeichnisse und Metadaten für Pakete erstellen Die ID des Pakets, zu dem das Modul gehört. Der Name des Moduls, der optional für die jeweilige Installation in der Modulverwaltung bearbeitet werden kann. Der Status des Moduls, der aktiv oder inaktiv sein kann Verzeichnisstruktur für Paket erstellen Um eigene Module zu entwickeln, müssen Sie zunächst die Paketstruktur erstellen. Diese Paketstruktur besteht aus einem Basisverzeichnis und Metadaten, in denen wesentliche Merkmale wie Typ oder Dateiname der einzelnen Module festgehalten werden. Ein Paket besteht dabei aus mindestens einem Modul, kann aber beliebig viele Module beliebigen Typs enthalten. Die grundlegende Verzeichnisstruktur für eigene Module ist dabei immer die selbe. Neben den PHP-Dateien enthält dieses Verzeichnis auch Metadaten in Form der modules.xml sowie Tabellenstrukturbeschreibungen. Diese Informationen werden von papaya CMS benötigt, damit die Module in der Modulverwaltung registriert und anschließend verwendet werden können. Pakete für papaya CMS müssen in ein Verzeichnis unterhalb von./papaya-lib/modules abgelegt werden. Dabei sollten eigene Pakete und Pakete von Drittanbietern von den Basispaketen unterschieden werden, die im papaya-release enthalten sind (Verzeichnisse free und _base). Zu diesem Zweck sollten Sie eigene Pakete innerhalb von./papayalib/modules/external/ installieren. Listing 3.36: Beispiel für ein Verzeichnis mit eigenem Paket 1./papaya-lib/modules/external/my_module Paketverzeichnis anlegen Um ein Paketverzeichnis anzulegen, gehen Sie wie folgt vor: 1. Legen Sie im Verzeichnis./papaya-lib/modules/external/ das Verzeichnis für Ihr Paket an. 2. Erstellen Sie innerhalb des Paketverzeichnisses das Unterverzeichnis DATA. 3. Erstellen Sie innerhalb des Paketverzeichnisses das Unterverzeichnis pics. 4. Erstellen Sie innerhalb des Unterverzeichnisses pics die Unterverzeichnisse 16x16, 22x22 und 48x48. 89

94 3 Basismodule für papaya CMS programmieren Nachdem Sie die Verzeichnisse angelegt haben, sollte Ihr Paketverzeichnis folgende Struktur aufweisen: 1./ 2./DATA/ 3./pics/ 4./pics/16x16/ 5./pics/22x22/ 6./pics/48x48/ Listing 3.37: Struktur eines Paket-Verzeichnisses Die Unterverzeichnisse und Metadateien des Pakets werden in folgender Tabelle ausführlich beschrieben. Paketinhalt./modules.xml./DATA/./pics/ Tabelle 3.8: Unterverzeichnisse und Metadateien eines Pakets Funktion Diese XML-Datei enthält alle wesentlichen Informationen zu jedem Modul des Pakets. Dazu gehört der Name der Quellcodedatei, der Name der PHP-Klasse, die GUID des Moduls sowie der Modultyp. Dieses optionale Verzeichnis enthält für jede Datenbanktabelle, die das Modul benutzt, eine separate XML-Datei. In dieser XML-Datei wird die Struktur der jeweiligen Datenbanktabelle beschrieben. Dieses optionale Unterverzeichnis enthält Icons für Backend-Anwendungen von papaya CMS. Dazu gehört beispielsweise das Icon für das Admin-Modul sowie Icons, die für spezielle Funktionen im Bearbeitungsmenü der Anwendung benutzt werden können. Das pics-unterverzeichnis enthält für die drei Standard-Icongrößen in papaya CMS jeweils Unterverzeichnisse (16x16, 22x22, 48x48). Anschließend können Sie damit beginnen, Module für papaya CMS zu schreiben. Damit diese Module in papaya CMS verwendet werden können, müssen Sie die modules.xml- Datei erstellen. Näheres dazu erfahren Sie im folgenden Abschnitt. 90

95 3.4 Verzeichnisse und Metadaten für Pakete erstellen modules.xml erstellen Damit die Module aus Ihrem Paket in papaya CMS verwendet werden können, müssen Sie diese in die Datei modules.xml eintragen. Anschließend können Sie die Module Ihres Pakets papaya CMS registrieren, Benutzen Sie dazu die Modulscan-Funktion in der Modulverwaltung. Um eine modules.xml zu schreiben, gehen Sie bitte wie folgt vor: 1. Legen Sie im Basisverzeichnis Ihres Pakets eine Datei mit dem Namen modules.xml an. 2. Öffnen Sie die Datei mit einem Texteditor. 3. Fügen Sie eine XML-Deklaration sowie das Dokumentenelement <modulegroup> hinzu: Listing 3.38: XML-Deklaration und Dokumentenelement eingeben 1 <?xml version="1.0"?> 2 <modulegroup> 3 </modulegroup> 4. Fügen Sie ein <name>-element mit dem Namen des Pakets und ein <description>- Element mit einer kurzen Beschreibung des Paketinhalts in die modules.xml ein: Listing 3.39: Paketname und -beschreibung eingeben 1 <?xml version="1.0"?> 2 <modulegroup> 3 <name>beispielpaket</name> 4 <description>dieses Paket macht dies und das.</description> 5 </modulegroup> 5. Fügen Sie das Element <modules> ein. Dieses Element enthält für jedes Modul aus Ihrem Paket ein <module>-element: Listing 3.40: Modulbeschreibung eingeben 1 <?xml version="1.0"?> 2 <modulegroup> 3 <name>beispielpaket</name> 4 <description>dieses Paket macht dies und das.</description> 5 <modules> 6 <module type="" guid="" name="" class="" file="" outputfilter=""></module> 7 <module type="" guid="" name="" class="" file="" outputfilter="" glyph=""></module> 8 <!-- Weitere Module können folgen --> 9 </modules> 10 </modulegroup> 6. Tragen Sie für jedes Attribut die notwendigen Inhalte ein, um die Eigenschaften des Moduls zu spezifizieren: Listing 3.41: Moduleigenschaften spezifizieren 91

96 3 Basismodule für papaya CMS programmieren 1 <?xml version="1.0"?> 2 <modulegroup> 3 <name>beispielpaket</name> 4 <description>dieses Paket macht dies und das.</description> 5 <modules> 6 <module type="box" 7 guid="6a5e040c d3e378f6e91c6a3dc" 8 name="example box" 9 class="example" 10 file="actbox_example.php" 11 outputfilter="yes"></module> 12 <module type="admin" 13 guid="3a0db2ac6d10ce827666f568057e538c" 14 name="example" 15 class="admin_example" 16 file="admin_example.php" 17 outputfilter="no" 18 glyph="example.png"></module> 19 <!-- Weitere Module können folgen --> 20 </modules> 21 </modulegroup> Näheres zu den Attributen des <module>-elements erfahren Sie in Tabelle 3.10, S Geben Sie für jedes Modul einen Beschreibungstext innerhalb des <module>-elements ein: Listing 3.42: Modulbeschreibung eintragen 1 <?xml version="1.0"?> 2 <modulegroup> 3 <name>beispielpaket</name> 4 <description>dieses Paket macht dies und das.</description> 5 <modules> 6 <module type="box" 7 guid="6a5e040c d3e378f6e91c6a3dc" 8 name="example box" 9 class="example" 10 file="actbox_example.php" 11 outputfilter="yes">dieses Boxmodul stellt zufällige Beispielinhalte aus der 12 Beispielanwendung dar.</module> 13 <module type="admin" 14 guid="3a0db2ac6d10ce827666f568057e538c" 15 name="example" 16 class="admin_example" 17 file="admin_example.php" 18 outputfilter="no" 19 glyph="example.png">die Example-Anwendung dient dazu, Beispielinhalte zu pflegen, 20 die in der Beispielbox ausgegeben werden können</module> 21 <!-- Weitere Module können folgen --> 22 </modules> 23 </modulegroup> 8. Speichern Sie die Datei ab. Das Paket kann nun im Backend von papaya CMS in der Modulverwaltung registriert werden. Führen Sie dazu den Modulscan aus. Im Folgenden wird das Content-Modell der modules.xml beschrieben. 92

97 3.4 Verzeichnisse und Metadaten für Pakete erstellen Das Element <modulegroup> Das Element <modulegroup> umfasst die gesamte Paketdefinition und besteht aus folgenden Elementen: Element name description modules Tabelle 3.9: Content-Modell des Elements <modulegroup> Funktion Obligatorisch: Dieses Element enthält den Namen des Pakets. Der Name wird in der Modulverwaltung von papaya CMS dargestellt. Obligatorisch. Dieses Element enthält eine kurze Beschreibung des Pakets. Obligatorisch: Enthält für jedes Modul des Pakets ein <module>-element. tables Optional, enthält für jede Datenbanktabelle ein <table>-element. Das Element <modules> Das Element <modules> enthält <module>-elemente. Jedes <module>-element beschreibt ein Modul, wobei die Eigenschaften des Moduls über Attribute erfasst werden. <module>-elemente sollten den optionalen Beschreibungstext enthalten, der die Funktion des Moduls beschreibt. Der Nutzer erfährt darüber hinaus, wie man das Modul einsetzen kann. Der Beschreibungstext wird in der Modulverwaltung angezeigt, wenn Sie das Modul in der Modulverwaltung von papaya CMS anklicken. Die Attribute des <module>- Elements sind in der folgenden Tabelle aufgeschlüsselt: Tabelle 3.10: Moduleigenschaften Attribut Bedeutung Notwendig type Modultyp, siehe Tabelle 2.1, S. 10. ja guid Eindeutiger 32-stelliger hexadezimaler Schlüssel. ja name Der kurze und aussagekräftige Name des Moduls. ja class Name der PHP-Klasse des Moduls. ja file Name der PHP-Datei, die die Modulklasse enthält. Der Dateiname ist grundsätzlich gleich dem Klassennamen plus der Endung.php. ja 93

98 3 Basismodule für papaya CMS programmieren Tabelle 3.10: Moduleigenschaften (forts.) Attribut Bedeutung Notwendig outputfilter yes, wenn ein Ausgabefilter notwendig ist, andernfalls no. Das Attribut kann auch ganz wegfallen, wobei es so interpretiert wird, als hätte es den Wert yes. Dieses Attribut ist nur für Content-Module vom Typ page und box relevant. nein glyph Icon für Adminmodule nein Die GUID identifiziert das Modul eindeutig. Dadurch ist es möglich, Dateinamen und Klassennamen von Modulen zu ändern und sogar Module in andere Pakete zu verschieben, ohne etwas in der Installation ändern zu müssen. Lediglich der Modulscan muss erneut durchgeführt werden. Sie finden einen md5-zufallsgenerator z.b. unter Sie können das Attribut glyph bei Administrationsmodulen angeben, um der Anwendung ein Icon zuzuweisen. Näheres zu Icons für Anwendungen erfahren Sie in Abschnitt 3.4.4, S. 95. Das Element <tables> Das optionale <tables>-element enthält <table>-elemente, die alle für das Paket notwendigen Datenbanktabellen aufführen. Ein <table>-element beschreibt dabei eine Tabelle, wobei der Name der Tabelle ohne Tabellen-Präfix im Attribut name aufgeführt wird. Standardmäßig lautet der Tabellenpräfix papaya. Da es jedoch erlaubt ist, abweichende Tabellenpräfixe zu benutzen, wird das Tabellenpräfix aus Gründen der Flexibilität nicht im Namen aufgeführt. Die Struktur der Tabelle muss in der Datei./DATA/table_tabellenname.xml definiert sein. Der Name dieser Datei wird dabei aus dem Namen abgeleitet, der im name-attribut des <table>-elements angegeben ist. Näheres dazu, wie die Tabellen in die modules. xml eingetragen werden, erfahren Sie in Abschnitt 3.4.6, S. 97. In Abschnitt 3.4.5, S. 96 erfahren Sie, wie Sie die XML-Dateien mit der Strukturbeschreibung der Datenbanktabellen erstellen und in die modules.xml einfügen können. 94

99 3.4 Verzeichnisse und Metadaten für Pakete erstellen Icons für das Admin-Modul denieren Jedes Paket kann eigene Icons für die Anwendung mitliefern, die im Unterverzeichnis. /DATA/pics des Pakets gespeichert werden. Sie können die Icons in der Anwendung selbst für Buttons oder Icons zu benutzen oder als Icon für die Anwendung selbst. Das Icon für die Anwendung sollte in allen drei Größen (16x16, 22x22, 48x48) vorhanden sein. Icon in der modules.xml im glyph-attribut benutzen Um das Icon für die Anwendung zu benutzen, gehen Sie wie folgt vor: 1. Speichern Sie das Icon in den Größen 16x16, 22x22 und 48x48 Pixel in den jeweiligen Unterverzeichnissen des Verzeichnisses./DATA/pics/ ab. Im folgenden Beispiel soll die Datei example.png benutzt werden: Listing 3.43: Icon-Dateien in Unterverzeichnisse./DATA/pics/ speichern 1./DATA/pics/16x16/example.png 2./DATA/pics/22x22/example.png 3./DATA/pics/48x48/example.png 2. Geben Sie den Dateinamen in der modules.xml im Attribut glyph an: <module 3 type="admin" 4 guid="3a0db2ac6d10ce827666f568057e538c" 5 name="example" 6 class="admin_example" 7 file="admin_example.php" 8 outputfilter="no" 9 glyph="example.png">description</module> Listing 3.44: Icon im Attribut glyph angeben 3. Speichern Sie die modules.xml ab und führen Sie in der Modulverwaltung den Modulscan durch, damit die geänderten Daten aus der modules.xml eingelesen werden. Icons für das Bearbeitungsmenü benutzen Näheres dazu, wie Sie Icons für das Bearbeitungsmenü benutzen können, erfahren Sie in Abschnitt 4.3.3, S

100 3 Basismodule für papaya CMS programmieren Tabellenstrukturdatei mit papaya CMS erstellen Wenn Sie eine Tabellenstrukturdatei erstellen möchten, müssen Sie diese nicht von Hand schreiben. Um eine neue Tabelle zu einem Modulpaket hinzuzufügen, gehen Sie wie folgt vor: 1. Legen Sie die Tabelle mit allen benötigten Feldern in der Datenbank an. Denken Sie dabei auch an die Indices. 2. Fügen Sie den Namen der Tabelle in die modules.xml ein, siehe Abschnitt 3.4.6, S Führen Sie in der Modulverwaltung von papaya CMS den Modulscan aus. Die referenzierten Tabellen werden im Abschnitt Paketinhalt unter Tabellen aufgeführt. In der Modulverwaltung von papaya CMS ist die Tabelle im Tabellenbereich des Pakets sichtbar. Zusätzlich wird ein Infodialog angezeigt, der auf die fehlende Strukturdatei hinweist. Sie können die Tabellenstruktur über die papaya-funktion Tabelle exportieren in der Modulverwaltung als XML-Datei speichern. Gehen Sie dazu wie folgt vor: 1. Klicken Sie in der Modulverwaltung auf die Tabelle, deren Strukturinformationen Sie als XML-Datei speichern möchten. 2. Klicken Sie im Bearbeitungsmenü auf Tabelle exportieren. Ein Downloaddialog wird angezeigt. Die Datei wird mit folgendem Dateinamensformat auf Ihrem Rechner gespeichert: Listing 3.45: Dateinamensformat der heruntergeladenen Tabellenstrukturdatei 1 table_<tabellenname>_<datum>.xml 3. Kopieren Sie die Datei nun auf den Server in das Unterverzeichnis./DATA/ Ihres Paketverzeichnisses. Ändern Sie dabei den Dateinamen in das folgende Namensformat um, indem Sie das Datum aus dem Namen entfernen. 1 table_<tabellenname>.xml Listing 3.46: Namensformat der Tabellenstrukturdateien Wenn Sie nun in der Modulverwaltung die Tabelle anklicken, wird der Infodialog mit der Warnung über die fehlende Tabellenstrukturdatei nicht mehr angezeigt. Näheres zur Modulverwaltung erfahren Sie in papaya CMS 5: Handbuch für Administratoren, Kapitel

101 3.4 Verzeichnisse und Metadaten für Pakete erstellen Tabellen in modules.xml referenzieren Wenn Ihr Paket eigene Datenbanktabellen benutzt, müssen Sie für jede Tabelle eine XML- Datei mit einer Strukturbeschreibung anlegen und im Unterverzeichnis DATA in Ihrem Paket speichern. Diese XML-Strukturdateien müssen Sie in die modules.xml eintragen, damit die Modulverwaltung die Tabellendaten nutzen kann. Wenn das Paket auf eine andere papaya-installation installiert wird, kann papaya CMS anhand der Tabellenstrukturbeschreibungen die notwendigen Tabellen für das Paket erzeugen.! Tabellenstrukturdatei erstellenes ist nicht notwendig, die Tabellenstrukturdatei manuell zu erstellen. Sie können dazu die Funktion Tabelle exportieren aus der Modulverwaltung im Backend von papaya CMS benutzen. Näheres dazu erfahren Sie in Abschnitt 3.4.5, S. 96 Um die Tabellendokumente in der modules.xml zu registrieren, gehen Sie bitte wie folgt vor: 1. Öffnen Sie die modules.xml mit einem Texteditor. 2. Fügen Sie, sofern noch nicht vorhanden, unterhalb des <modules>-elements das Element <tables> ein: Listing 3.47: <tables>-element einfügen 1 <?xml version="1.0"?> 2 <modulegroup> 3 <name>beispielpaket</name> 4 <description>dieses Paket macht dies und das.</description> 5 <modules> 6 <!-- Weitere Module können folgen --> 7 </modules> 8 <tables> 9 </tables> 10 </modulegroup> 3. Fügen Sie für jede Tabelle ein <table>-element ein. Der Name der Tabelle wird dabei im Attribut name angegeben, wobei der Tabellenpräfix ausgelassen wird: Listing 3.48: Tabellen in <table>-elemente eintragen 1 <?xml version="1.0"?> 2 <modulegroup> 3 <name>beispielpaket</name> 4 <description>dieses Paket macht dies und das.</description> 5 <modules> 6 <!-- Weitere Module können folgen --> 7 </modules> 8 <tables> 9 <table name="example_basicstuff" /> 10 <table name="example_otherstuff" /> 11 </tables> 12 </modulegroup> 97

102 3 Basismodule für papaya CMS programmieren 4. Speichern Sie die Datei ab. Das Paket kann nun im Backend von papaya CMS in der Modulverwaltung registriert werden. Die XML-Dateien mit den Tabellenstrukturen werden im Verzeichnis./DATA/ gespeichert, wobei der Dateiname das Präfix table_ erhält Anwendung als Paket ausliefern Um ein papaya-modul oder eine ganze Anwendung als Paket auszuliefern, gehen Sie wie folgt vor: 1. Erstellen Sie ein spezielles Exportverzeichnis mit der kompletten Verzeichnisstruktur, in das die Dateien auf dem Zielsystem installiert werden sollen. Der Name des Exportverzeichnisses sollte dem Format <Modulname>-<Version>.<Unterversion> entsprechen, beispielsweise example-module In dieses Exportverzeichnis kopieren Sie die Dateien Ihres Pakets. Sofern Sie ein Versionsverwaltungssystem verwenden, entfernen Sie unbedingt alle von diesem System erstellten Metadaten (z.b. die.svn-verzeichnisse ). Versionsverwaltungssysteme wie Subversion bieten auch Exportfunktionen an, die keine Metadaten erstellen. 3. Fügen Sie dem Paket eine Datei mit den Lizenzangaben bei. Für papaya CMS gilt die GPL Wenn Ihr Paket Seiten- oder Boxmodule enthält, sollten Sie Beispieltemplates beifügen. Diese Templates können durch die Nutzer einfach an die eigene Webseitenvorlage angepasst werden. 5. Legen Sie Ihrem Programmpaket auch eine README.txt bei. Die README.txt ist eine Textdatei, in der Sie Installationsanweisungen für den Nutzer angeben. Lizenzangaben beachten papaya CMS unterliegt der GPL (GNU General Public License). Diese verpflichtet Sie als Nutzer und Entwickler von Erweiterungen, bei der Weitergabe des Programmcodes bestimmte Regeln einzuhalten. Dazu gehört, dass Sie alle Ableitungen des papaya-basissystems ebenso unter die GPL stellen und den Quellcode frei zur Verfügung stellen. Mit Ableitungen sind entweder direkte Änderungen am Basissystem von papaya CMS gemeint oder eigene Module und Anwendungen, die Sie von den Basisklassen ableiten. Wenn Sie also Ihre Anwendung zum Download anbieten möchten, sollten Sie ihrem Programmcode auch eine Kopie der GPL beilegen. 98

103 3.4 Verzeichnisse und Metadaten für Pakete erstellen Dateien und Verzeichnisse in ein TGZ- oder ZIP-Archiv packen Um das Paket weiterzugeben, sollten Sie es in ein TGZ- oder ZIP-Archiv packen. Sie können dazu Ihr Lieblingspackprogramm verwenden, beispielsweise WinZip, 7zip, file-roller, ark oder die Kommandozeilenbefehle tar oder zip. Stellen Sie sicher, dass das Archiv das Paketverzeichnis mit Versionsnummer explizit enthält, damit beim Entpacken die Dateien in einem eigenen Verzeichnis landen. Beim Packen mit tar oder zip sollten Sie sich eine Ebene über dem Exportverzeichnis befinden. Bei GUI-Programmen wählen Sie bitte das Exportverzeichnis aus, nicht alle einzelnen darin enthaltenen Dateien und Verzeichnisse. Das folgende Listing stellt dar, wie Sie ein Paket mit dem Packprogramm tar erstellen können: Listing 3.49: Paket mit tar erstellen 1 $ tar cvzf example-module-0.1.tgz example-module-0.1 Das folgende Listing stellt dar, wie Sie das Paket mit dem Packprogramm zip erstellen können: Listing 3.50: Paket mit zip erstellen 1 $ zip -r example-module-0.1.zip example-module

104 3 Basismodule für papaya CMS programmieren 100

105 4 Module für das Backend programmieren In diesem Kapitel erfahren Sie, wie Sie eigene Anwendungen für das Backend schreiben können. 4.1 Eigene Anwendungen schreiben Anwendungen sind Programme, die papaya CMS um spezielle Funktionen erweitern. Anwendungen können aus verschiedenen Modulen für die Seiten- oder Boxausgabe bestehen. Sie enthalten jedoch insbesondere spezielle Administrationsmodule, mit denen die Benutzeroberfläche im Backend aufgebaut wird. Diese Administrationsmodule stellen Einund Ausgabeschnittstellen zur Verfügung, mit denen der Benutzer Daten eingeben und bearbeiten oder Einstellungen vornehmen kann. Folgende Schritte sind notwendig um eine eigene Anwendung zu erstellen: 1. Erstellen Sie ein Basismodul, das Daten in die Datenbank einfügen, sie aktualisieren und auslesen kann, siehe Abschnitt 4.1.2, S Erstellen Sie ein Administrationsmodul, in dem Sie bestehende Datensätze ansehen und ändern sowie neue Datensätze hinzufügen können, siehe Abschnitt 4.1.3, S Fügen Sie dem Administrationsmodul optional einige zusätzliche Konfigurationsoptionen hinzu, siehe Abschnitt 4.1.4, S Erstellen Sie ein Ausgabemodul, dass die Daten aus der Datenbank ausliest und in eine XML-Ausgabe überführt, siehe Abschnitt 4.1.5, S Erstellen Sie ein Konnektor-Modul, mit dem Sie die Daten für beliebige andere Module zur Verfügung stellen, siehe Abschnitt 4.1.6, S Das im Folgenden beschriebene Beispielprogramm soll Sammlungen (Collections) einfacher Text- oder Bildbausteine (Stickers), verwalten und diese ausgeben können. 101

106 4 Module für das Backend programmieren Beispiel-Anwendung Stickers Die nachfolgenden Programmierbeispiele werden anhand der Klassen der Anwendung Stickers beschrieben. Stickers kann zufällig ausgewählte Zitate oder Bilder anzeigen und funktioniert auf vergleichbare Weise wie das UNIX-Programm fortune. Das Zitat oder die Bildreferenz wird in einem Sticker-Objekt verwaltet, das weitere Metadaten wie den Namen des Urhebers des Zitats oder Bildes enthält. Sticker werden immer einer Sammlung zugeordnet, wobei jede Sammlung beliebig viele Sticker-Einträge verwalten kann. Die Stickers -Anwendung kann darüber hinaus beliebig viele Sammlungen verwalten Basismodul für Datenbankzugrie schreiben Bei komplexeren Anwendungen gibt es häufig mehrere Ausgabemodule (Seite/Box), die auf Daten in einer Datenbanktabelle zugreifen müssen. Das Administrationsmodul benötigt lesenden und schreibenden Zugriff auf die Datenbank. Es ist daher günstig, zumindest den Datenbankzugriff in einer separaten Klasse zu abstrahieren, die von den einzelnen Modulen gemeinsam genutzt werden kann. Schreibzugriffe können gegebenenfalls auch im Administrationsmodul implementiert werden. Bei papaya CMS wird die Klasse für den Datenbankzugriff zumeist als Basisklasse bezeichnet. Der Konvention nach beginnen Dateiund Klassenname mit base_. Die Basisklasse soll Sticker-Datensätze und Sammlungsdatensätze erstellen, laden, aktualisieren, und löschen können. Für die Ausgabemodule wird eine Methode bereitgestellt, die alle Sticker einer Sammlung ganz oder abschnittsweise zurückgibt sowie eine Methode, die einen zufälligen Sticker zurückgibt. Jede Sammlung soll einen Titel und eine Beschreibung haben. Jeder Sticker soll Text oder Bild und optional eine Autorenangabe enthalten. Für die Basisklasse ergeben sich also folgende Anwendungsfälle: Sticker hinzufügen Sticker laden Sticker bearbeiten Sticker löschen Sammlung hinzufügen Sammlung laden Sammlung bearbeiten Sammlung löschen Alle Sticker einer Sammlung laden 102

107 4.1 Eigene Anwendungen schreiben Eine Auswahl an Sticker laden (mit Start-ID und Offset). Zufälligen Sticker (einer Sammlung) laden Struktur der Datenbanktabellen Die Daten für die Anwendung werden auf zwei Tabellen verteilt. Die erste Datenbanktabelle mit dem Namen papaya_sticker enthält alle Sticker-Daten: Tabelle 4.1: Struktur der Tabelle papaya_sticker Feld Datentyp Beschreibung sticker_id integer ID, Primärschlüssel collection_id integer ID, externer Schlüssel der Sammlung sticker_text string Text des Stickers sticker_image string Bild-ID sticker_author string Autor des Textes Die zweite Datenbanktabelle enthält alle Daten, die zu einer Sammlung gehören: Tabelle 4.2: Struktur der Tabelle papaya_sticker_collections Feld Datentyp Beschreibung collection_id integer ID, Primärschlüssel collection_title string Titel der Sammlung collection_description string Beschreibungstext der Sammlung Die beiden Tabellen stehen in einer 1-n-Beziehung zueinander. Genau eine Sammlung kann beliebig viele Sticker-Elemente enthalten, während ein Sticker-Element immer nur einer Sammlung angehören kann. Diese Relation wird dadurch festgehalten, dass zu jedem Sticker-Eintrag die ID der zugehörigen Sammlung über das Feld collection_id festgehalten wird. Klassen mit Datenbankzugriff werden grundsätzlich von der Systemklasse base_db abgeleitet. Das folgende Listing stellt das Grundgerüst der Klasse base_stickers dar, das die oben erwähnten Anwendungsfälle in Form von Methodenrümpfen enthält: 103

108 4 Module für das Backend programmieren Listing 4.1: Grundgerüst der Basisklasse base_stickers 1 require_once(papaya_include_path. system/sys_base_db.php ); 2 3 class base_stickers extends base_db { 4 function construct() {} 5 function addsticker($collectionid, &$data) {} 6 function addcollection($title, $description) {} 7 function updatesticker($collectionid, $stickerid, &$data) {} 8 function updatecollection($collectionid, $title, $description) {} 9 function deletesticker($stickerid) {} 10 function deletecollection($collectionid) {} 11 function getcollections() {} 12 function getstickersbycollection($collectionid, $limit, $offset) {} 13 function getsticker($stickerid) {} 14 function getrandomsticker($collectionid) {} 15 } Im folgenden wird nun die Implementation des Konstruktors sowie der einzelnen Methoden vorgestellt. Konstruktor implementieren Damit der möglicherweise gesetzte Tabellen-Präfix genutzt wird, müssen Sie Tabellennamen abhängig von der Konstanten PAPAYA_DB_TABLEPREFIX definieren. Eine passende Stelle dafür ist der Konstruktor. Rufen Sie zunächst den Elternkonstruktor auf, damit dort vorgenommene Initialisierungen trotz Überladen durchgeführt werden: Listing 4.2: Konstruktor der Basisklasse 1 function construct() { 2 parent:: construct(); 3 $this->tablesticker = PAPAYA_DB_TABLEPREFIX. _sticker ; 4 $this->tablecollections = PAPAYA_DB_TABLEPREFIX. _sticker_collections ; 5 } Soll Ihre Anwendung mit PHP4 kompatibel sein, fügen Sie den PHP4-Konstruktor (entspricht dem Klassennamen) ein. Der Einfachheit halber ruft der PHP4-Konstruktor den PHP5- Konstruktor construct() auf: 1 function base_stickers() { 2 base_sticker:: construct(); 3 } Listing 4.3: PHP4-Konstruktor der Basisklasse Der PHP4-Konstruktor delegiert also die Aufgabe an den PHP5-Konstruktor. 104

109 4.1 Eigene Anwendungen schreiben Daten zur Datenbank hinzufügen Verwenden Sie base_db::databaseinsertrecord() um einen Datensatz der Datenbanktabelle hinzuzufügen. Der erste Parameter ist der Tabellenname, den Sie im Attribut $tablesticker abgelegt haben. Der zweite Parameter ist der Name des Autoincrement-Feldes, dessen Wert Sie zurückbekommen wollen um die Datensatz-Id zu erhalten. Benötigen Sie den Wert nicht, so geben Sie NULL an: Sie unterdrücken damit die Abfrage nach der soeben eingefügten ID. Der dritte Parameter enthält die einzufügenden Daten. Das Daten-Array enthält den Namen der Felder und die dazugehörigen Daten in einer Liste von Schlüssel-Wert-Paaren. Diese Daten werden in die angegebene Tabelle geschrieben. Außer der Collection-ID werden alle anderen Daten aus dem Parameter $data ausgelesen. Sie können also die übermittelten Formularparameter direkt an diese Methode weitergeben. Vorher sollten Sie ggf. überprüfen, ob die Daten gesetzt sind. Verwenden Sie Typecasting um der Datenbankabstraktion einen Wert mit dem richtigen Datentyp zu übergeben. Listing 4.4: Implementation der Methode addsticker() 1 function addsticker($collectionid, &$data) { 2 $data = array( 3 collection_id => (int)$collectionid, 4 sticker_text => (string)$data[ sticker_text ], 5 sticker_image => (string)$data[ sticker_image ], 6 sticker_authr => (string)$data[ sticker_author ], 7 ); 8 $stickerid = $this->databaseinsertrecord( 9 $this->tablesticker, 10 sticker_id, 11 $data 12 ); 13 if ($stickerid) { 14 return $stickerid; 15 } 16 return FALSE; 17 } Entsprechend wird die Methode addcollection() implementiert: Listing 4.5: Implementation der Methode addcollection() 1 function addcollection($title, $description) { 2 $data = array( 3 collection_title => (string)$title, 4 collection_description => (string)$description, 5 ); 6 $collectionid = $this->databaseinsertrecord( 7 $this->tablecollections, 8 collection_id, 9 $data 10 ); 11 if ($collectionid) { 12 return $collectionid; 13 } 105

110 4 Module für das Backend programmieren 14 return FALSE; 15 }! Sie können Daten auch einzeln an eine Datenbankmethode übergeben. Jedes Datenfeld wird also in einem separaten Parameter übergeben. In der Methode addcollection() wird etwa der Wert des Titels und des Beschreibungstextes jeweils als separater Parameter übergeben: 1 function addcollection($title, $description) { } Diese Vorgehensweise erhöht bei wenigen Parametern die Lesbarkeit. Bei drei oder mehr Parametern verringert sich die Lesbarkeit jedoch wieder und die Flexibilität sinkt. Stellen Sie sich vor, Sie fügen zwei weitere Datenbankfelder hinzu oder entfernen eines. Bei Einzelübergabe müssen Sie die Parameterliste und alle Ihre Aufrufe modifizieren. Dieses Problem besteht nicht, wenn Sie die Daten in einem Array übergeben. Die Methode addsticker() ist beispielsweise so implementiert, dass die Daten in einem Array (Parameter $data) übergeben werden: 1 function addsticker($collectionid, &$data) { } Wenn Sie die Stickers-Tabelle in der Datenbank ändern sollten, müssen Sie nur das $data-array erweitern. Daten in der Datenbank ändern Verwenden Sie die Methode base_db::databaseupdaterecord(), um einen bestehenden Datensatz zu aktualisieren. Übergeben Sie Tabellennamen, Updatedaten sowie eine SQL-Bedingung als Parameter. Nach einer Plausibilitätsprüfung bauen Sie das Daten- Array wie bei der Methode addsticker() auf. Übergeben Sie als Bedingung ein assoziatives Array mit dem Feldnamen sticker_id als Schlüssel und der Sticker-ID als Wert. Daraus wird die SQL-Bedingung konstruiert, die bestimmt, welche Datensätze zu ändern sind. Listing 4.6: Implementation der Methode updatesticker() 1 function updatesticker($collectionid, $stickerid, &$data) { 2 if ($collectionid > 0 && $stickerid > 0) { 3 $data = array( 4 collection_id => $collectionid, 5 sticker_text => $data[ sticker_text ], 106

111 4.1 Eigene Anwendungen schreiben 6 sticker_image => $data[ sticker_image ], 7 sticker_author => $data[ sticker_author ], 8 ); 9 $condition = array( 10 sticker_id => $stickerid, 11 ); 12 return (FALSE!== $this->databaseupdaterecord($this->tablesticker, $data, $condition)); 13 } 14 } Entsprechend arbeitet die Methode updatecollection(): Listing 4.7: Implementation der Methode updatecollection() 1 function updatecollection($collectionid, $title, $description) { 2 if ($collectionid > 0 && $title!= ) { 3 $data = array( 4 collection_title => (string)$title, 5 collection_description => (string)$description, 6 ); 7 $condition = array( 8 collection_id => $this->params[ col_id ], 9 ); 10 return (FALSE!== $this->databaseupdaterecord( 11 $this->tablecollections, $data, $condition) 12 ); 13 } 14 } Daten aus der Datenbank entfernen Um einen Datensatz zu löschen, können Sie die Methode base_db::databasedeleterecord( ) benutzen. Diese benötigt als ersten Parameter den Namen der Tabelle, auf die sich die Löschaktion bezieht, als zweiten Parameter die Löschbedingung in Form eines assoziativen Arrays. Der Array-Schlüssel bezeichnet den Feldnamen, im Normalfall der Primärschlüssel, der Array-Wert den Wert dieses Feldes beim zu löschenden Datensatz. Im folgenden Beispiel wird die Methode zum Löschen von Sticker-Einträgen vorgestellt. Die Löschbedingung besteht aus dem Feldnamen sticker_id und der ID des zu löschenden Feldes: Listing 4.8: Implementation der Methode deletesticker() 1 function deletesticker($stickerid) { 2 if ($stickerid > 0) { 3 $condition = array( sticker_id => $stickerid); 4 return (FALSE!== $this->databasedeleterecord( 5 $this->tablesticker, $condition)); 6 } 7 } Die Methode zum Löschen einer Sammlung wird ähnlich implementiert. Sie sollten jedoch zunächst alle Sticker der Sammlung löschen, damit keine verwaisten Datensätze zurückbleiben. 107

112 4 Module für das Backend programmieren Listing 4.9: Implementation der Methode deletecollection() 1 function deletecollection($collectionid) { 2 if ($collectionid > 0) { 3 $condition = array( collection_id => $collectionid); 4 if (FALSE!== $this->databasedeleterecord($this->tablesticker, $condition)) { 5 return (FALSE!== $this->databasedeleterecord( 6 $this->tablecollections, $condition) 7 ); 8 } 9 } 10 } Daten aus der Datenbank auslesen Im Folgenden geht es um die Implementation der Ausgabemethoden. Um bestehende Daten verwalten zu können, benötigen Sie in der Stickers-Anwendung eine Liste aller Sammlungen, alle Sticker einer Sammlung und schließlich einzelne Sammlungen oder Sticker zur Bearbeitung. Für einfache SQL-Abfragen steht Ihnen die Methode base_db::databasequeryfmt( ) zur Verfügung. Sie Formulieren die SQL-Abfrage dabei in einem String, wobei Sie für den Tabellennamen den sprintf()-platzhalter %s einsetzen. Übrigens können Sie beliebige Positionen im SQL mit Platzhaltern besetzen, die durch Parameter ersetzt werden, die der Methode databasequeryfmt() als Array übergeben werden. Als ersten Parameter erwartet die Methode databasequeryfmt() den SQL-String, als zweiten Parameter ein Array mit den Parametern. databasequeryfmt() arbeitet wie die PHP-Funktion vprintf() und ersetzt alle Platzhalter im SQL-String durch die Parameter im Parameter- Array. Die folgende Methode liest alle Sammlungen aus der Tabelle aus. Anstelle des Tabellennamens steht im SQL-String ein Platzhalter, der durch den Tabellennamen im Parameter- Array $params ersetzt wird: Listing 4.10: Implementation der Methode getcollections() 1 function getcollections() { 2 $result = FALSE; 3 $sql = "SELECT collection_id, collection_title, collection_description 4 FROM %s 5 "; 6 $params = array($this->tablecollections); 7 if ($res = $this->databasequeryfmt($sql, $params)) { 8 $result = array(); 9 while ($row = $res->fetchrow(db_fetchmode_assoc)) { 10 $result[$row[ collection_id ]] = $row; 11 } 12 } 13 return $result; 14 } 108

113 4.1 Eigene Anwendungen schreiben Die Rückgabe von base_db::databasequeryfmt() ist eine Instanz von dbresult_ base (in system/db/base.php), die ein einfaches Arbeiten mit der Ergebnismenge erlaubt. Verwenden Sie dbresult_base::fetchrow() um den nächsten Datensatz aus dem Ergebnis zu holen. Der Parameter DB_FETCHMODE_ASSOC bewirkt, dass der Feldname als Schlüssel des Ergebnisarrays verwendet wird. Der Standardwert der Parameters, DB_FETCHMODE_DEFAULT, bewirkt, dass die Schlüssel durchnummeriert werden, in der Reihenfolge der Feldnamen im SQL-Befehl. Beispiel für eine Rückgabe der Methode getcollections(): Listing 4.11: Beispielausgabe für die Methode getcollections() 1 array( 2 1 => array( 3 collection_id => 1, 4 collection_title => meine Sammlung, 5 collection_description => einige tolle Zitate, 6 ), 7 2 => array( 8 collection_id => 2, 9 collection_title => lustige Bilder, 10 collection_description => witzige Bilder, die ich im Internet gefunden habe, 11 ), 12 ); Um alle Sticker einer Sammlung zu erhalten, implementieren Sie z.b. folgende Methode: Listing 4.12: Implementation der Methode getstickersbycollection() 1 function getstickersbycollection($collectionid, $limit, $offset) { 2 $result = FALSE; 3 if ($collectionid > 0) { 4 $sql = "SELECT sticker_id, collection_id, sticker_text, sticker_image, 5 sticker_author 6 FROM %s 7 WHERE collection_id = %d 8 ORDER BY sticker_id ASC 9 "; 10 $params = array($this->tablesticker, $collectionid); 11 if ($res = $this->databasequeryfmt($sql, $params, $limit, $offset)) { 12 $result = array(); 13 while ($row = $res->fetchrow(db_fetchmode_assoc)) { 14 $result[$row[ sticker_id ]] = $row; 15 } 16 $this->abscount = $res->abscount(); 17 } 18 } 19 return $result; 20 } Wenn Sie eine Bedingung in die SQL-Abfrage einbauen, verwenden Sie als Platzhalter bei Strings %s mit einfachen Anführungszeichen, bei Zahlen %d. Im obigen Beispiel wird eine numerische SQL-Bedingung benutzt, für die ein entsprechender Platzhalter %d gesetzt ist. Für diese SQL-Bedingung wird an das $params-array der Wert $collectionid angehängt. Die Reihenfolge der Platzhalter in der Abfrage muss der Reihenfolge der Parameter entsprechen. 109

114 4 Module für das Backend programmieren! Die Vorteile von Platzhaltern in SQL-Abfragen sind Übersichtlichkeit, Flexibilität und Sicherheit:Die Abfrage ist übersichtlicher, weil sie nicht mit Variablen gespickt ist. Die Abfrage ist flexibler, weil häufig nur das params-array geändert werden muss. Die Abfrage ist sicherer, weil die Methode databasequeryfmt() das Maskieren der Eingaben übernimmt. Dies reduziert die Gefahr von SQL-Injections immens. Die Parameter $limit und $offset werden als dritten und vierten Parameter der Methode databasequeryfmt() übergeben. $limit beinhaltet die maximale Anzahl auszulesender Datensätze, während $offset angibt, um wie viele Datensätze versetzt die Abfrage Datensätze zurückliefern soll. Die Methode databasequeryfmt() kümmert sich dabei um die DBMS-spezifische Verwendung der Abfrageeinschränkungen. Beispiel für eine Rückgabe der Methode getstickersbycollection(): Listing 4.13: Beispielausgabe für die Methode getstickersbycollection() 1 array( 2 1 => array( 3 sticker_id => 1, 4 collection_id => 2, 5 sticker_text => Exploits of a Mom, 6 sticker_image => 263d7b3d1e0fbac620d0c5c634bcb2ed, 7 sticker_author => xkcd, 8 ), 9 2 => array( 10 sticker_id => 2, 11 collection_id => 1, 12 sticker_text => It is by the fortune of God that, in this country, 13 we have three benefits: freedom of speech, freedom of thought, and the wisdom never to use either., 14 sticker_image =>, 15 sticker_author => Mark Twain, 16 ), 17 ); Das folgende Listing stellt die Implementation der getsticker()-methode vor. Diese Methode liest genau einen Stickereintrag anhand der übergebenen Sticker-ID aus der Datenbank aus: Listing 4.14: Implementation der Methode getsticker() 1 function getsticker($stickerid) { 2 $result = FALSE; 3 if ($stickerid > 0) { 4 $sql = "SELECT sticker_id, collection_id, sticker_text, sticker_image, 5 sticker_author 6 FROM %s 7 WHERE sticker_id = %d 8 ORDER BY sticker_id ASC 9 "; 10 $params = array($this->tablesticker, $stickerid); 11 if ($res = $this->databasequeryfmt($sql, $params)) { 12 return $res->fetchrow(db_fetchmode_assoc); 13 } 14 } 15 return $result; 110

115 4.1 Eigene Anwendungen schreiben 16 } Im Unterschied zu getstickersbycollection() bezieht sich die WHERE-Bedingung hier auf die sticker_id, und nicht auf die collection_id. Da wir nur einen Datensatz zurückbekommen, können wir die Rückgabe von base_db::fetchrow() mit return direkt weitergeben. Für die spätere Boxausgabe muss ein zufälliger Sticker aus der Datenbank geladen werden. Das folgende Listing stellt die Implementation einer entsprechenden Datenbankabfrage vor: Listing 4.15: Implementation der Methode getrandomsticker() 1 function getrandomsticker($collectionid) { 2 $result = FALSE; 3 $randomorder = $this->databasegetsqlsource( RANDOM ); 4 5 $sql = "SELECT sticker_id, collection_id, sticker_text, 6 sticker_image, sticker_date, sticker_author, 7 sticker_source, sticker_source_url, sticker_explanation 8 FROM %s 9 WHERE collection_id = %d 10 ORDER BY $randomorder 11 "; 12 $params = array($this->tablesticker, $collectionid); 13 if ($res = $this->databasequeryfmt($sql, $params, 1)) { 14 return $res->fetchrow(db_fetchmode_assoc); 15 } 16 return $result; 17 } Der einzige Parameter $collectionid der Methode ist die ID der Sammlung, zu der der Sticker gehört. Mit der Methode base_db::databasegetsqlsource() wird die DBMS-spezifische Variante der Zufallsfunktion ausgelesen. Bei MySQL ist der Rückgabewert RAND(). Übergeben Sie der Methode base_db::databasequeryfmt() als dritten Parameter (maximale Anzahl der angeforderten Datensätze) die Zahl 1. Dadurch wird die Rückgabe auf einen Datensatz (LIMIT 1) beschränkt. Damit ist die Klasse base_stickers vollständig, sodass dem Einsatz im Administrationsmodul nichts mehr im Wege steht Administrationsmodul schreiben Das Administrationsmodul besteht in papaya CMS aus zwei Klassen. Die erste Klasse ist das eigentliche Administrationsmodul und leitet von base_module ab. Sie erhält das Klassenpräfix edmodule_. Die eigentliche Darstellungs- und Anwendungslogik ist dabei in eine weitere Klasse ausgelagert. Diese Klasse leitet direkt von der Basisklasse der Anwendung ab und erhält das Klassenpräfix admin_. 111

116 4 Module für das Backend programmieren Die edmodule-klasse Instanziiert ein Objekt der admin-klasse und definiert darüber hinaus noch Zugriffsrechte für die Klasse. Die Klasse edmodule_stickers Die Klasse edmodule_stickers ist sehr klein, da sie lediglich ein Attribut und eine Methode enthält. Das folgende Listing stellt das Grundgerüst der Klasse dar: Listing 4.16: Grundgerüst der edmodule_stickers-klasse 1 require_once(papaya_include_path. system/base_module.php ); 2 3 class edmodule_stickers extends base_module { 4 var $permissions; 5 function execmodule() {} 6 } Mit require_once wird die Basisklasse base_module.php aus dem Basissystem geladen. Die Klasse edmodule_stickers leitet anschließend von base_module ab. Der Konvention nach beginnen Dateiname und Klassenname mit dem Präfix edmodule_. Das Attribut $permissions ist ein Array, das eine Liste von Rechten enthält. Sie können bestimmte Funktionen in der Klasse admin_stickers mit Rechten verknüpfen, die in diesem Array definiert worden sind. Dadurch können die Funktionen nur durch berechtigte Nutzer oder Gruppen verwendet werden. Die entsprechenden Berechtigungen können in der Benutzerverwaltung erteilt werden, indem die Rechte aus dem Attribut $permissions mit der Benutzergruppe oder direkt mit dem Benutzer verknüpft werden. 1 var $permissions = array( 2 1 => Manage, 3 ); Listing 4.17: Attribut $permissions mit Rechten Im obigen Listing ist lediglich das Recht Manage definiert worden. Nutzer, die dieses Recht haben, können mit der Anwendung arbeiten und alle Funktionen der Anwendung nutzen. Sie können jedoch auch ein sehr viel feineres Rechtesystem anlegen. Erstellen Sie dazu weitere Rechte wie Edit oder Delete und verknüpfen Sie sie mit den entsprechenden Funktionen. Ein Nutzer muss also in diesem Fall mindestens das Recht Manage haben, um die Stickers-Anwendung benutzen zu können. Um Daten anlegen und bearbeiten zu können, benötigt er das Recht Edit. Um Daten Löschen zu können, ist schließlich das Recht Delete notwendig. Damit können Sie einzelnen Nutzern oder Gruppen explizit das Recht einräumen Datensätze zu erstellen, nicht jedoch sie zu löschen. Ein Nutzer muss zumindest das Recht Manage besitzen, damit er das Modul verwenden darf. Das folgende Listing stellt die Implementation der Methode execmodule() dar: 112

117 4.1 Eigene Anwendungen schreiben Listing 4.18: Implementation der Methode execmodule() 1 function execmodule() { 2 if ($this->hasperm(1, TRUE)) { 3 include_once(dirname( FILE ). /admin_stickers.php ); 4 $stickers = &new admin_stickers($this); 5 $stickers->module = &$this; 6 $stickers->images = &$this->images; 7 $stickers->msgs = &$this->msgs; 8 $stickers->layout = &$this->layout; 9 $stickers->authuser = &$this->authuser; 10 $stickers->initialize(); 11 $stickers->execute(); 12 $stickers->getxml(); 13 } 14 } Wenn Sie das Modul im Backend von papaya CMS starten, ruft die Modulverwaltung von papaya CMS als erstes die Methode execmodule() der Klasse edmodule_stickers auf. Zunächst wird mit der Methode base_module::hasperm() geprüft, ob der aktuelle Nutzer das Recht hat, das Modul zu verwenden. Wenn ja, wird das eigentliche Administrationsmodul eingebunden, instanziiert und initialisiert. Dazu werden einige Attribute als Referenz weitergegeben, die in der folgenden Tabelle näher aufgeschlüsselt werden: Attribut $module $images $msgs $layout $authuser Tabelle 4.3: Attribute, die an das Adminmodul übergeben werden Bedeutung Die Instanz von edmodule, also eine Subklasse von base_module. Diese wird benötigt, um beispielsweise die Modul-GUID zu ermitteln. Im Admin-Modul kann über das Attribut $this->module->guid auf die GUID zugegriffen werden. Enthält die papaya-internen Icons. Enthält das globale Messages-Array, an das mit $this- >addmsg() Meldungen angehängt werden. Das Layout-Objekt für das Backend. Es handelt sich dabei um eine Instanz von papaya_xsl. Mit diesem Objekt werden Dialog- sowie Formularelemente mit add(), addleft() oder addright() hinzugefügt oder Layoutparameter mit setparam() gesetzt. Objekt mit Daten des angemeldeten Benutzers, Instanz von base_auth. Anschließend werden die Methoden initialize(), execute() und getxml() des Adminobjekts aufgerufen. Mit initialize() wird das Objekt für die Ausführung vorbereitet. Dazu werden nötige Hilfsobjekte instanziiert und Default-Parameter gesetzt. In 113

118 4 Module für das Backend programmieren execute() werden vom Anwender ausgelöste Aktionen durchgeführt. Dazu gehört beispielsweise das Auswählen, Hinzufügen, Ändern oder Löschen eines Datensatzes. Der Name der Methode getxml() ist missverständlich, da nicht XML an die aufrufende Instanz zurückgegeben wird. Stattdessen wird das Objekt angewiesen, Ausgabe-XML an das Layoutobjekt weiterzugeben. Registrieren Sie das Modul in der modules.xml als ein Modul vom Typ admin. Dort können Sie auch ein Icon angeben, das in der Anwendungsliste erscheint. Nähere Informationen zur Registrierung von Modulen finden Sie im Kapitel Abschnitt 3.4.3, S. 91. Die Klasse admin_stickers Die Klasse admin_stickers beinhaltet die Darstellungs- und Anwendungslogik des Administrationsmoduls. Vom Benutzer angestoßene Aktionen werden durchgeführt, die Ausgabedaten zusammengestellt und in das Ausgabe-XML überführt. Das folgende Listing stellt das Grundgerüst des Administrationsmoduls vor. Die einzelnen Funktionen sind als Methodenrümpfe aufgelistet: Listing 4.19: Grundgerüst des Administrationsmoduls 1 require_once(dirname( FILE ). /base_stickers.php ); 2 3 class admin_stickers extends base_stickers { 4 var $paramname; 5 function initialize() {} 6 function getxml() {} 7 function getmenubarxml() {} 8 function getcollectionslist() {} 9 function getstickerslist() {} 10 function initializecollectiondialog($cmd, $loadparams = TRUE) {} 11 function getdeletecollectionconfirmdialog() {} 12 } Die Klasse admin_stickers erweitert base_stickers und erhält dadurch die zuvor implementierten Datenbankfunktionen. Diese Datenbankfunktionen werden in der Klasse admin_stickers nun um die Anwendungs- und Darstellungslogik erweitert. papaya CMS verwendet Parameternamen in POST und GET um Kollisionen zwischen Anwendungen zu vermeiden. Der Identifikator jeder Anwendung wird im Attribut $paramname festgelegt: 1 var $paramname = st ; Listing 4.20: Attribut $paramname der Klasse admin_stickers Das Attribut $paramname wird von Link-Methoden wie getweblink() in base_object genutzt. Nähere Informationen zu Links finden Sie in Abschnitt 3.3.4, S

119 4.1 Eigene Anwendungen schreiben Die Methode initialize() Als erstes wird von edmodule_sticker die Methode initialize() aufgerufen. Diese Methode initialisiert zunächst die Sessions und macht den Parameter col_id persistent: Listing 4.21: Implementation der Methode initialize() 1 function initialize() { 2 $this->sessionparamname = PAPAYA_SESS_.$this->paramName; 3 $this->initializeparams(); 4 $this->sessionparams = $this->getsessionvalue($this->sessionparamname); 5 $this->initializesessionparam( col_id ); 6 $this->setsessionvalue($this->sessionparamname, $this->sessionparams); 7 8 $this->moduleimages[ sticker ] 9 = sprintf( module:%s/pics/stickers.png, $this->module->guid); $this->layout->setparam( COLUMNWIDTH_LEFT, 50% ); 12 $this->layout->setparam( COLUMNWIDTH_CENTER, 0 ); 13 $this->layout->setparam( COLUMNWIDTH_RIGHT, 50% ); include_once(papaya_include_path. system/base_btnbuilder.php ); 16 $this->menubar = &new base_btnbuilder; 17 $this->menubar->images = &$this->images; if (!isset($this->collections)) { 20 $this->collections = $this->getcollections(); 21 } 22 } Mehr Informationen zur Verwendung der Session finden Sie in Abschnitt 3.2, S. 70. Um eine zentrale Stelle für modulspezifische Icons zu haben, werden die anwendungsspezifischen Icons im Attribut $moduleimages abgelegt. Mehr Informationen zur Verwendung von modulspezifischen Icons finden Sie in Abschnitt 4.3.3, S Das Layout der Administrationsoberfläche wird in zwei gleichgroße Spalten unterteilt. Dies wird dadurch erreicht, dass entsprechende Parameter im Layoutobjekt gesetzt werden, indem die Methode $this->layout->setparam() aufgerufen wird. Dabei werden die linke und die rechte Spalte des Layoutobjekts jeweils auf eine Breite von 50 % gesetzt, während die Breite der mittleren Spalte auf 0 gesetzt wird. Im folgenden Schritt wird das Attribut $this->menubar mit der Instanz der Klasse base_ btnbuilder initialisiert. Mit dieser Klasse wird die Menüleiste zusammengestellt. Die Instanz $this->menubar erhält noch die Referenz auf das Attribut $this->images. Im letzten Schritt der Initialisierungsmethode werden noch alle bestehenden Sammlungen in das Attribut $this->collections geladen. Damit stehen sie für den Rest des Programmablaufes zur Verfügung. 115

120 4 Module für das Backend programmieren Die Methode getxml() Sie können die Programmlogik implementieren, ohne die Ausgabe implementiert zu haben. Für den Zweck dieses Tutorials ist es nützlicher, zunächst die Ausgabe zu betrachten und dann die Logik, da diese Vorgehensweise anschaulicher ist. Für die Ausgabe benötigen Sie ein Menü, das Bearbeitungsfunktionen zur Verfügung stellt, eine Übersicht über alle Sammlungen, eine Liste der Sticker in der ausgewählten Sammlung und Bearbeitungsformulare. Die Ausgabe wird von der Methode getxml() gesteuert, deren Implementation im folgenden Listing dargestellt wird: Listing 4.22: Implementation der Methode getxml() 1 function getxml() { 2 $this->layout->addmenu($this->getmenubarxml()); 3 $this->layout->addleft($this->getcollectionslist()); 4 $this->layout->addleft($this->getstickerslist()); 5 if (isset($this->dialog) && is_object($this->dialog) && 6 base_dialog == get_class($this->dialog)) { 7 $this->layout->addright($this->dialog->getdialogxml()); 8 } 9 } Die Methode getxml() ruft die XML-Ausgabemethoden der Klasse auf und fügt die Ausgaben in das Layoutobjekt $this->layout ein. Im ersten Schritt wird mit addmenu() das Bearbeitungsmenü dem Layout-Objekt hinzugefügt. Die Ausgabe hierzu kommt von der Methode getmenubarxml(). Anschließend wird der linken Spalte des Content-Bereichs mit der Layoutobjektmethode addleft() eine Liste mit den Sammlungen hinzugefügt. Schließlich wird auch die Liste mit den Stickers in die linke Spalte des Content- Bereichs eingefügt. Dazu wird wieder die Layoutobjektmethode addleft() benutzt. Sofern ein Dialogobjekt im Klassenattribut $this->dialog vorhanden ist, wird die XML- Ausgabe des Dialogs in die rechte Spalte des Content-Bereichs gesetzt. Dazu wird die Methode $this->layout->addright() des Layoutobjekts benutzt. Das Dialogobjekt $this->dialog besitzt die Methode getdialogxml() für die XML-Ausgabe, die in diesem Zusammenhang genutzt wird. In den folgenden Abschnitten werden die Methoden getmenubarxml(), getcollectionslist ) sowie getstickerslist() im Detail vorgestellt. Die Methode getmenubarxml() Mit der Methode getmenubarxml() wird das XML für das Bearbeitungsmenü erzeugt: Listing 4.23: Implementation der Methode getmenubarxml() 116

121 4.1 Eigene Anwendungen schreiben 1 function getmenubarxml() { 2 $result = ; 3 $this->menubar->addbutton( add collection, $this->getlink( 4 array( cmd => add_collection )), actions-folder-add, 5 add a new collection, 6 (!empty($this->params[ cmd ]) && $this->params[ cmd ] == add_collection )); 7 if (isset($this->params[ col_id ]) && $this->params[ col_id ] > 0) { 8 $this->menubar->addbutton( delete collection, $this->getlink(array( 9 cmd => del_collection, 10 sticker_id => $this->params[ col_id ])), actions-folder-delete, 11 delete the current collection, 12 (!empty($this->params[ cmd ]) && $this->params[ cmd ] == del_collection )); 13 $this->menubar->addseperator(); 14 $this->menubar->addbutton( add sticker, $this->getlink(array( 15 cmd => add_sticker, 16 col_id => $this->params[ col_id ])), actions-page-add, 17 add a sticker to the current collection, 18 (!empty($this->params[ cmd ]) && $this->params[ cmd ] == add_sticker )); 19 } 20 if ($menu = $this->menubar->getxml()) { 21 $result = sprintf( <menu>%s</menu>.lf, $menu); 22 } 23 return $result; 24 } Das Klassenattribut $menubar wurde in der Methode initialize() mit einer Instanz von base_btnbuilder belegt. Diesem Objekt werden in der Methode getmenubarxml( ) Buttons hinzugefügt. Dazu wird die Methode addbutton() aufgerufen, die fünf Parameter enthält: Der erste Parameter ist der Buttontext. Er wird automatisch übersetzt. Der zweite Parameter ist der Link, der bei einem Klick auf den Button aufgerufen wird. Er wird mit der Methode getlink() erzeugt. Der dritte Parameter enthält den Iconnamen und entspricht dem Schlüssel des Icons im Array $this->images. Der vierte Parameter enthält einen Tooltip-Text, die bei Mouseover eingeblendet wird. Der fünfte Parameter ist ein boolescher Wert, der aussagt, ob der Button eingedrückt dargestellt werden soll oder nicht. Standardmäßig wird stets der Button Add collection dargestellt. Wenn der Parameter $ this->params[ col_id ] gesetzt ist und einen Wert größer 0 besitzt, ist eine Sammlung ausgewählt. In diesem Fall werden zusätzlich noch die Buttons Delete collection sowie Add Sticker dargestellt. Zusätzlich werden die Buttons, deren Funktionen sich auf eine Sammlung beziehen, von den Sticker-spezifischen Buttons durch einen Separator getrennt. Hierzu fügt die Methode addseparator() einen vertikalen grafischen Trenner in die Toolbar ein. Bei der Ausgabe in XML wird jeder Button als <button>-element ausgegeben. Damit diese Elemente ein übergeordnetes Element erhalten, wird die Ausgabe in ein <menu>-tag 117

122 4 Module für das Backend programmieren eingebettet. Die Rückgabe der Methode getmenubarxml() entspricht folgender XML- Struktur: Listing 4.24: Beispielausgabe der Methode getmenubarxml() 1 <menu> 2 <button title="add collection" 3 href="module_edmodule_stickers.php?st[cmd]=add_collection" 4 glyph="actions/folder-add.png" 5 hint="add a new collection" 6 target="_self"/> </menu> Die Methode getcollectionslist() Die Methode getcollectionslist() erzeugt eine Listview der vorhandenen Sammlungen und gibt diese als XML-Präsentation zurück. Eine Listview ist eine tabellarische Darstellung der Daten. Das folgende Listing stellt die Struktur der XML-Ausgabe vor: Listing 4.25: Beispielausgabe der Methode getcollectionslist() 1 <listview title="titel"> 2 <items> 3 <listitem title="name"><subitem>inhalt</subitem></listitem> </items> 6 </listview> Näheres zum Aufbau von Listviews erfahren Sie in Kapitel 6, S Grundsätzlich gehen Sie wie folgt vor, wenn Sie eine Listviewausgabe erstellen: 1. Sie initialisieren die Ergebnisvariable $result. 2. Sie laden die benötigten Daten in ein Array. 3. Sie fügen ein öffnendes <listview>-element in die Ausgabe und geben der Liste einen Titel. 4. Sie geben für jedes Datenelement ein <listitem>-element aus. Ist die Datenmenge leer, geben Sie optional eine Statusmeldung für den Benutzer aus. 5. Sie fügen ein schließendes <listview>-element der Ergebnisvariablen $result hinzu. Damit wird die Listview geschlossen. 6. Geben Sie mit return die $result-variable zurück. Das folgende Listing stellt das Grundgerüst der Methode getcollectionslist() vor: 118

123 4.1 Eigene Anwendungen schreiben Listing 4.26: Grundgerüst der Methode getcollectionslist() 1 function getcollectionslist() { 2 $result = ; 3 $this->collections = $this->getcollections(); 4 $result.= sprintf( <listview title="%s">.lf, 5 papaya_strings::escapehtmlchars($this->_gt( Collections ))); 6 if (is_array($this->collections)&& count($this->collections) > 0) { 7 //... 8 } else { 9 $result.= sprintf( <status>%s</status>, $this->_gt( No collections found. )); 10 } 11 $result.= </listview> ; 12 return $result; 13 } Im Grundgerüst der Methode getcollectionslist() werden zunächst die Sammlungen geladen. Anschließend wird ein öffnendes <listitem>-element mit dem passenden Titel an die $result-variable gehängt. Wenn die Liste der Sammlungen $this->collections leer ist, wird eine Statusmeldung in einem <status>-element ausgegeben, andernfalls werden die <listitem>-elemente ausgegeben. Anschließend wird das <listitem>- Element geschlossen und die $result-variable per return zurückgegeben. Wenn der Titel für das <listitem>-element in das title-attribut ausgegeben wird, muss der Text mit der Methode papaya_strings::escapehtmlchars() maskiert werden. Damit wird verhindert, dass das XML von Eingaben wie ">< zerstört wird. Für die Ausgabe der <listitem>-elemente werden alle Objekte des Datenarrays iteriert. Für jeden Datensatz wird dabei ein <listitem>-element ausgegeben. Die <listitem> -Elemente werden alle durch ein <item>-element umschlossen, wie das folgende Listing darstellt: Listing 4.27: <listitem>-ausgabe in getcollectionslist() 1 $result.= <items>.lf; 2 foreach($this->collections as $collectionid => $collection) { 3 if (isset($this->params[ col_id ]) && $collectionid == $this->params[ col_id ]) { 4 $selected = selected="selected" ; 5 } else { 6 $selected = ; 7 } 8 $result.= sprintf( <listitem image="%s" title="%s" href="%s" %s>.lf, 9 $this->images[ items-folder ], 10 papaya_strings::escapehtmlchars($collection[ collection_title ]), 11 $this->getlink(array( cmd => edit_collection, col_id => $collectionid)), $selected); 12 $result.= </listitem> ; 13 } 14 $result.= </items>.lf; Bei der Ausgabe der <listitem>-elemente wird überprüft, ob die aktuelle Sammlung ausgewählt ist. Ist dies der Fall, erhält das <listitem>-element das Attribut selected= "selected". Dieses Attribut bewirkt, dass das betroffene <listitem>-element in der Benutzeroberfläche hervorgehoben wird. 119

124 4 Module für das Backend programmieren Das folgende Listing stellt die Beispiel-Ausgabe der getcollectionslist()-methode dar: Listing 4.28: Beispielausgabe der Methode getcollectionslist() 1 <items> 2 <listitem image="items/folder.png" 3 title="meine Sammlung" 4 href="module_edmodule_stickers.php?st[cmd]=edit_collection&st[col_id]=1" 5 selected="selected"> 6 </listitem> 7 </items> Die Methode getstickerslist() soll eine Liste aller in einer Sammlung vorhandenen Sticker anzeigen. Die Methode ist ähnlich implementiert wie getcollectionslist( ). Im folgenden Listing ist das Grundgerüst der getstickerslist()-methode dargestellt: Listing 4.29: Grundgerüst der Methode getstickerslist() 1 function getstickerslist() { 2 $result = ; 3 if (isset($this->params[ col_id ]) && $this->params[ col_id ] > 0) { 4 $stickers = $this->getstickersbycollection($this->params[ col_id ], 100, 0); 5 $result.= sprintf( <listview title="%s">.lf, 6 papaya_strings::escapehtmlchars($this->_gt( Stickers ))); 7 if (is_array($stickers) && count($stickers) > 0) { 8 //... 9 } else { 10 $result.= sprintf( <status>%s</status>.lf, $this->_gt( No stickers in this collection. )); 11 } 12 $result.= </listview> ; 13 } 14 return $result; 15 } Die Methode getstickerslist() Die Listview für die Stickerliste wird wie bei der Sammlung ausgegeben. Bei der <items>- Ausgabe unterscheidet sich das Vorgehen, weil drei Spalten benötigt werden: 1. Sticker-ID 2. Sticker-Titel 3. Löschfunktion (Im Gegensatz zu Sammlungen, die über den Button im Bearbeitungsmenü gelöscht werden) Listing 4.30: <listitem>-ausgabe in getstickerslist() 1 $result.= <items>.lf; 2 foreach($stickers as $stickerid => $sticker) { 3 if (isset($this->params[ sticker_id ]) && $this->params[ sticker_id ] == $stickerid) 120

125 4.1 Eigene Anwendungen schreiben 4 $selected = selected="selected" ; 5 } else { 6 $selected = ; 7 } 8 $result.= sprintf( <listitem image="%s" title="#%d" href="%s" %s>.lf, 9 $this->moduleimages[ sticker ], $stickerid, 10 $this->getlink(array( cmd => edit_sticker, sticker_id => $stickerid)), 11 $selected); 12 $result.= sprintf( <subitem><a href="%s">%s</a></subitem>.lf, 13 $this->getlink(array( cmd => edit_sticker, sticker_id => $stickerid)), 14 papaya_strings::truncate(strip_tags($sticker[ sticker_text ]))); 15 $result.= sprintf( <subitem><a href="%s"><glyph src="%s" /></a></subitem>.lf, 16 $this->getlink(array( cmd => del_sticker, sticker_id => $stickerid)), 17 $this->images[ actions-page-delete ]); 18 $result.= </listitem> ; 19 } 20 $result.= </items>.lf; Für das Icon in der ersten Spalte wird das Icon aus dem Stickers-Paket benutzt ( sticker ), das zuvor in der initialize()-methode gesetzt worden ist. Der Text in der zweiten Spalte wird als Link ausgegeben. Wenn der Nutzer auf diesen Link klickt, wird der Sticker mit der Bearbeiten-Funktion geöffnet. Für die Löschfunktion in der dritten Spalte wird ein <glyph>-element für das Icon ausgegeben (nur die erste Spalte (das <listitem>-element) unterstützt das image-attribut). Das <glyph>-element wird mit einem Link-Element (<a href=""></a>) umgeben, das mit der Löschen-Funktion verknüpft ist. Listing 4.31: Beispielausgabe der Methode getstickerslist() 1 <listview title="stickers"> 2 <items> 3 <listitem image="module:fadd3cc21cdfd5dba2492f6d7cd059b1/pics/stickers.png" 4 title="#1" 5 href="module_edmodule_stickers.php?st[cmd]=edit_sticker&st[sticker_id]=1"> 6 <subitem> 7 <a href="module_edmodule_stickers.php?st[cmd]=edit_sticker&st[sticker_id]=1"> 8 It is by the fortune of God that, in this country, we have three benefits:... 9 </a> 10 </subitem> 11 <subitem> 12 <a href="module_edmodule_stickers.php?st[cmd]=del_sticker&st[sticker_id]=1"> 13 <glyph src="actions/page-delete.png" /> 14 </a> 15 </subitem> 16 </listitem> 17 </items> 18 </listview> Die Methode execute() Im Programmablauf wird als zweites die Methode execute() aufgerufen. In dieser Methode wird zunächst überprüft, ob ein Befehl übermittelt wurde. Anschließend entscheidet die Methode anhand des Befehlsparameters $this->params[ cmd ], welche Funktion ausgeführt wird: 121

126 4 Module für das Backend programmieren 1 function execute() { 2 if (!empty($this->params[ cmd ])) { 3 switch ($this->params[ cmd ]) { 4 case add_collection : 5 //... 6 break; 7 case add_sticker : 8 //... 9 break; 10 case edit_collection : 11 // break; 13 case edit_sticker : 14 // break; 16 case del_collection : 17 // break; 19 case del_sticker : 20 // break; 22 } 23 } 24 } Listing 4.32: Grundaufbau der execute()-methode Der Befehlsparameter wird in einer Switch-Case-Konstruktion ausgewertet. Je nach Befehl werden entsprechende Funktionen ausgeführt. Im Prinzip kann man zwei verschiedene Arten von Befehlen unterscheiden: 1. Ein Befehl zum Anlegen oder Bearbeiten eines Datensatzes führt dazu, das eine Eingabemaske dargestellt wird. Der Nutzer kann Daten eingeben oder bestehende Daten bearbeiten. 2. Ein Befehl zum Löschen eines Datensatzes führt dazu, dass ein Dialog mit einer Sicherheitsabfrage dargestellt wird. Der Nutzer muss bestätigen, dass der Datensatz gelöscht werden soll. Wenn Sie also den Befehl zum Darstellen einer Eingabemaske implementieren wollen, gehen Sie wie folgt vor: 1. Initialisieren Sie das entsprechende Formular. 2. Prüfen Sie, ob Formulardaten übermittelt worden sind. 3. Führen Sie die Methode aus, mit der die Validität der Formulardaten überprüft werden. 4. Wenn die Daten gültig sind, schreiben Sie die Daten mit der Datenbankmethode aus der base-klasse in die Datenbank. 5. Wenn der Datensatz angelegt werden konnte oder die Änderung erfolgreich war, geben Sie eine entsprechende Infomeldung aus. Der komplette Abschnitt für den Befehl add_collection ist wie folgt implementiert: 122

127 4.1 Eigene Anwendungen schreiben Listing 4.33: Sammlung hinzufügen in execute()-methode case add_collection : 3 $this->initializecollectiondialog($this->params[ cmd ]); 4 if (isset($this->params[ submit ]) && $this->params[ submit ]) { 5 if ($this->dialog->checkdialoginput()) { 6 if ($collectionid = $this->addcollection($this->params[ collection_title ], 7 $this->params[ collection_description ])) { 8 $this->addmsg(msg_info, sprintf($this->_gt( Collection "%s" (#%d) added. ), 9 $this->params[ collection_title ], $collectionid); 10 $this->initializecollectiondialog($this->params[ cmd ], FALSE); 11 } 12 } 13 } 14 break; Zunächst wird die Methode initializecollectiondialog() ausgeführt, um das Eingabeformular für die Sammlung auszugeben. Anschließend wird überprüft, ob das Formular abgesendet worden ist. Dies ist der Fall, wenn im Parameter-Array der Wert submit enthalten ist und dieser Parameter den Wert TRUE besitzt. Wenn dies der Fall ist, können Sie die versendeten Formulardaten auf Validität prüfen. Dazu wird die Methode checkdialoginput( ) der base_dialog-instanz $this->dialog ausgeführt. Da das aktuelle Eingabeformular immer über $this->dialog erreichbar ist, können Sie die checkdialoginput( )-Methode einfach über diese Objektinstanz aufrufen. Wenn checkdialoginput() wahr ist, sind die Daten gültig und können in die Datenbank geschrieben werden. Dazu wird im obigen Listing die Methode addcollection() benutzt, die in der Basisklasse base_stickers implementiert worden ist. Dieser Methode wird der Titel sowie der Beschreibungstext der Sammlung übergeben. Wenn die Daten geschrieben werden konnten, gibt die Methode die ID der neu angelegten Sammlung zurück. Im letzten Schritt wird ein Infodialog dargestellt, der den Titel der Sammlung inklusive der ID in einem Infotext ausgibt. Der Infodialog wird mit der Methode addmsg() ausgegeben. Nähere Informationen zur Verwendung von addmsg() finden Sie in Abschnitt 5.3, S Alle notwendigen Daten wie der submit-parameter oder die Formulardaten kommen aus dem Eingabeformular, das in der Methode initializecollectiondialog() erzeugt wird. Im folgenden soll die Implementation dieser Methode vorgestellt werden. Die Methode initializecollectiondialog() Mit der Klasse base_dialog können Sie mit wenig Aufwand ein umfangreiches Formular gestalten. Weitere Informationen zur Verwendung finden Sie in der Dokumentation zur Klasse base_dialog. Der Konstruktor von base_dialog erwartet ein Elternob- 123

128 4 Module für das Backend programmieren jekt, den Parameternamen, eine Felddefinition (siehe Abschnitt 3.1.4, S. 64), Standarddaten für das Formular und versteckte Parameter. Der Vorgang einen bestehenden Datensatz zu ändern unterscheidet sich im Prinzip nicht von dem einen neuen Datensatz hinzuzufügen. Es müssen lediglich andere Methoden verwendet werden und die ID des zu ändernden Datensatzes mit übergeben werden. Die Werte, die bearbeitet werden, sind identisch. Die Methode initializecollectiondialog( ) können Sie deshalb mit geringem Aufwand so implementieren, dass sie beide Fälle behandeln kann: Hinzufügen und Bearbeiten. Listing 4.34: Implementation der Methode initializecollectiondialog() 1 function initializecollectiondialog($cmd, $loadparams = TRUE) { 2 include_once(papaya_include_path. system/base_dialog.php ); 3 $hidden = array( 4 cmd => $cmd, 5 submit => 1, 6 ); 7 if ($cmd == edit_collection && $this->params[ col_id ] > 0) { 8 $title = $this->_gt( Edit collection ); 9 $hidden[ col_id ] = $this->params[ col_id ]; 10 $data = $this->collections[$this->params[ col_id ]]; 11 $buttontitle = Save ; 12 } else { 13 $title = $this->_gt( Add a collection ); 14 $buttontitle = Add ; 15 $data = array(); 16 } 17 $fields = array( 18 collection_title => array( Title, isnohtml, TRUE, input, 200), 19 collection_description => array( Description, isnohtml, FALSE, textarea, 5), 20 ); 21 $this->dialog = &new base_dialog($this, $this->paramname, $fields, $data, $hidden); 22 if ($loadparams) { 23 $this->dialog->loadparams(); 24 } 25 $this->dialog->dialogtitle = $title; 26 $this->dialog->buttontitle = $buttontitle; 27 $this->dialog->inputfieldsize = large ; 28 } Sie erstellen ein Array $hidden für die versteckten Parameter. In diesem Array fügen Sie den Befehl ein, der ausgeführt werden soll (cmd = $cmd), sowie die Information, dass das Formular übermittelt wurde (submit = 1). Der Befehl wird dabei aus dem Parameter $cmd ausgelesen. Dadurch können Sie den selben Befehl für den Aufruf des Formulars über einen Link als auch für das Versenden des Formulars verwenden und dennoch unterscheiden, welcher Fall vorliegt. Im nächsten Schritt wird in der If-Abfrage getestet, ob ein bestehender Datensatz bearbeitet werden soll. In diesem Fall hat der Parameter $cmd den Wert edit_collection. Entsprechend diesem Befehl wird der Titel des Dialogs und des Button-Titels gesetzt. Außerdem wird das $data-array mit den bereits geladenen Daten der aktuell ausgewählten 124

129 4.1 Eigene Anwendungen schreiben Sammlung gefüllt. Das $hidden-array mit den versteckten Parametern wird noch um die ID der aktuell ausgewählten Sammlung erweitert. Wenn ein neuer Datensatz erstellt werden soll, lassen Sie das $data-array zunächst leer. Der Grund hierfür ist, dass das Formular in diesem Fall nicht mit bestehenden Daten vorbelegt werden soll. Der Konstruktor von base_dialog erwartet für den Parameter $data eine Referenz. Daher ist es nicht möglich, einfach ein leeres Array oder NULL zu übergeben. Das Array $data muss also stets initialisiert werden. Die Dialogfelder selbst werden im Array $fields angegeben. Für den Titel wird dabei ein einzeiliges Textfeld, für die Beschreibung ein mehrzeiliges Textfeld definiert. Die Dialogfelder werden nach dem selben Schema angelegt wie die Edit-Fields bei Content-Modulen. Näheres zu den Dialogfeldern erfahren Sie in Abschnitt 3.1.4, S. 64. Im letzten Schritt wird eine Instanz der Klasse base_dialog im Klassenattribut $this- >dialog angelegt. Übergeben Sie dem Konstruktor von base_dialog die Instanz der Klasse admin_stickers ($this), den Parameternamen sowie die Arrays mit den Formularfeldern, den Formulardaten und den versteckten Parametern. Dadurch kann auch aus der execute()-methode auf die Instanz zugegriffen werden. Laden Sie die bereits übermittelten Formulardaten in das Formular, wenn der Parameter $loadparamstrue ist. Dadurch können Fehleingaben bearbeitet werden ohne das ganze Formular erneut ausfüllen zu müssen. Wenn das Formular erfolgreich abgesendet wird, setzen Sie es zurück, indem Sie der Methode FALSE übergeben. Analog zu add_collection wird die Funktion für den Befehl add_sticker implementiert. Daten bearbeiten Um Daten zu bearbeiten, wird ebenso wie beim Hinzufügen von Daten das Eingabeformular initialisiert. Anschließend wird überprüft, ob das Formular abgesendet worden ist. Dies ist der Fall, wenn das Array $params den Parameter submit enthält. Der Wert des Parameters ist zudem 1 oder TRUE. Wenn dies der Fall ist, werden die übermittelten Daten mit der checkdialoginput()-methode überprüft. War die Überprüfung erfolgreich, wird der Datensatz mit der Datenbankmethode updatecollection() aus der Elternklasse base_stickers aktualisiert. Wenn die Daten erfolgreich geändert werden konnten, wird ein Infodialog mit einer entsprechenden Erfolgsmeldung ausgegeben: Listing 4.35: Sammlung bearbeiten (execute()-methode) case edit_collection : 3 $this->initializecollectiondialog($this->params[ cmd ]); 125

130 4 Module für das Backend programmieren 4 if (isset($this->params[ submit ]) && $this->params[ submit ]) { 5 if ($this->dialog->checkdialoginput()) { 6 if ($this->updatecollection($this->params[ col_id ], 7 $this->params[ collection_title ], $this->params[ collection_description ])) { 8 $this->addmsg(msg_info, $this->_gt( Collection updated. )); 9 unset($this->dialog); 10 } 11 } 12 } 13 break; Daten löschen Natürlich sollten Sie eine Funktion implementieren, um bestehende Einträge zu löschen. In papaya CMS werden Vorgänge, bei denen Datensätze umfassend geändert oder gelöscht werden, grundsätzlich mit einer Bestätigungsmeldung versehen. Der Benutzer muss den Vorgang also explizit bestätigen, damit Daten nicht bereits durch einen Buttonklick gelöscht werden. Auf diese Weise wird der versehentliche Datenverlust verhindert. Der Abschnitt del_collection in der Methode execute() ist wie folgt implementiert: Listing 4.36: Sammlung löschen (execute()) 1 case del_collection : 2 if (isset($this->params[ confirm ]) && $this->params[ confirm ]) { 3 if ($this->deletecollection($this->params[ col_id ])) { 4 $this->addmsg(msg_info, sprintf($this->_gt( Collection %d deleted. ), 5 $this->params[ col_id ])); 6 } 7 } else { 8 $this->layout->addright($this->getdeletecollectionconfirmdialog()); 9 } 10 break; Zunächst wird überprüft, ob der Parameter confirm gesetzt und wahr ist. Dies ist immer dann der Fall, wenn der Fragedialog vom Nutzer bestätigt worden ist. Bei einer Bestätigung wird der Datensatz gelöscht. Ist der Löschvorgang erfolgreich, wird dies dem Benutzer mit addmsg() mitgeteilt. Ist der Parameter nicht gesetzt, fügen Sie den Bestätigungdialog mit addright() in die rechten Spalte des Content-Bereichs hinzu. Der Löschvorgang bei Stickern wird analog implementiert. Datensätze werden also nur gelöscht, wenn der Nutzer dies explizit bestätigt hat. 126

131 4.1 Eigene Anwendungen schreiben Die Methode getdeletecollectionconfirmdialog() Verwenden Sie für Bestätigungsdialoge die Klasse base_msgdialog. Sie funktioniert ähnlich wie base_dialog, nur noch einfacher: Listing 4.37: Implementation von getdeletecollectionconfirmdialog() 1 function getdeletecollectionconfirmdialog() { 2 include_once(papaya_include_path. system/base_msgdialog.php ); 3 $hidden = array( 4 cmd => $this->params[ cmd ], 5 col_id => $this->params[ col_id ], 6 confirm => 1, 7 ); 8 9 $msg = sprintf( 10 $this->_gt( Do you really want to delete collection "%s" #%d? ), 11 $this->collections[$this->params[ col_id ][ collection_title ], 12 $this->params[ col_id ] 13 ); 14 $this->dialog = &new base_msgdialog( 15 $this, 16 $this->paramname, 17 $hidden, 18 $msg, 19 warning 20 ); 21 $this->dialog->buttontitle = Delete ; 22 return $this->dialog->getmsgdialog(); 23 } Um einen Dialog zu erzeugen, gehen Sie wie folgt vor: 1. Binden Sie die Klasse base_msgdialog ein. 2. Erstellen Sie ein $hidden-array, das die versteckt zu übermittelnden Parameter enthält. Üblicherweise sind das die durchzuführende Aktion (Parameter cmd), der Datensatz, auf den sich die Aktion bezieht (in diesem Fall der Parameter col_id), sowie die Bestätigung, dass der Benachrichtigungsdialog übermittelt wurde (confirm). 3. Erstellen Sie den Text der Bestätigungsfrage. Der Text muss den Nutzer darauf hinweisen, dass er durch einen Klick auf den Button einen Datensatz löscht. 4. Im letzten Schritt instanziieren Sie den Dialog. Der Konstruktor erhält als fünften Parameter den Dialogtyp, siehe Tabelle 4.4, S Setzen Sie als Button-Titel (Klassenattribut $this->dialog->buttontitle) den Namen der Funktion ein, die der Nutzer bestätigen muss. Beim Löschen von Datensätzen wäre dies beispielsweise die Beschriftung Löschen. 6. Die XML-Ausgabe des Dialogs wird schließlich mit $this->dialog->getmsgdialog( ) ausgegeben. Die folgende Tabelle schlüsselt alle Dialogtypen auf, die Sie für die Klasse base_msgdialog benutzen können: 127

132 4 Module für das Backend programmieren Dialogtyp question Tabelle 4.4: Mögliche Typen für den Messagedialog Bedeutung Einfache Bestätigungsabfrage warning Bestätigungsabfrage erhöhter Wichtigkeit info Bestätigung, dass der Benutzer die Information gelesen hat. error Bestätigung, dass der Benutzer die Fehlermeldung gelesen hat Moduloptionen hinzufügen Alle von base_plugin abgeleiteten Module können ihre eigenen Konfigurationsoptionen mitbringen. Diese sind in einem Array im Klassenattribut $pluginoptionfields enthalten. Im Grunde ist dieses Array ähnlich strukturiert wie die $editfields bei Content-Modulen. Der Unterschied besteht darin, dass diese Optionen in der Modulverwaltung bearbeitet werden und innerhalb einer Installation nur einen Wert haben, also unabhängig von einzelnen Seiten immer gleich sind. Die Idee hinter den Moduloptionen besteht darin, dass bestimmte seiten- oder boxübergreifenden Daten seitenunabhängig zur Verfügung gestellt werden. Beispielsweise kann die ID einer bestimmten Seite von verschiedenen Seiten- und Boxmodulen eines Pakets benötigt werden. Die auf diese Weise verlinkte Seite kann spezielle Funktionen enthalten, auf die über eine Weiterleitung mit zusätzlichen Parametern zugegriffen werden kann. Im folgenden Listing wird die Beispieldefinition für eine Moduloption dargestellt: Listing 4.38: Definition von Moduloptionen ($pluginoptionfields) var $pluginoptionfields = array( 3 my_value => array( Option 1, isnum, TRUE, input, 5), 4 ); 5... Wenn Sie in der Modulverwaltung das entsprechende Modul auswählen, stehen Ihnen die Moduloptionen unter dem Reiter Optionen zur Verfügung: 128

133 4.1 Eigene Anwendungen schreiben Abbildung 4.1: Konfiguration von Moduloptionen im Backend Und so greifen Sie auf den konfigurierten Wert im Modul zu: Listing 4.39: Moduloptionen mittels papaya_module_options laden 1 include_once(papaya_include_path. system/papaya_module_options.php ); 2 $moduleoptionsobj = &new papaya_module_options(); 3 $moduleoptions = $moduleoptionsobj->getoptions($this->guid); 4 $value = $moduleoptions[ MY_VALUE ]; Aus dem Schlüsselwort my_value ist beim Laden MY_VALUE geworden. Dadurch lassen sich Moduloptionen besser von normalen Werten unterscheiden Output-Klasse für Seiten und Boxen schreiben Wenn Seiten- und Boxmodule umfangreicher werden, kann es sein, dass Sie eigene Methoden zur Inhaltskonfiguration verwenden. Auch die Ausgabemöglichkeiten können sich vervielfältigen, so dass die Klasse sehr groß wird. Das ist aus mehreren Gründen ungünstig: Bei der Ausgabe wird der Code für die Konfiguration mitgeparst. Bei der Administration wird der Code für die Ausgabe mitgeparst. Die Klasse wird unübersichtlicher. Der weitaus häufigere Fall ist der, dass die Ausgabelogik umfangreicher wird. Wenn die Ausgabelogik in eine separate Klasse ausgelagert wird, muss dieser Code beim Konfigurieren der Seite im Backend nicht mehr geladen werden. Zudem kann es sein, dass Sie mehrere Ausgabemodule erstellen wollen, die teilweise das selbe XML ausgeben. Eine zentrale Output-Klasse kann in diesem Fall Redundanzen vermeiden und die Performance verbessern. 129

134 4 Module für das Backend programmieren! Die Seiten- oder Boxkonfiguration in den $editfields sollten Sie unter bestimmten Umständen als Moduloptionen abkapseln. Dies bietet sich an, wenn einer der folgenden Punkte zutrifft: Die $editfields von Seiten- oder Boxmodulen sind in mehrere Gruppen unterteilt und sehr umfangreich. Sie verwenden umfangreiche eigene Formulare zur Inhaltsverwaltung. Für einfache $editfields mit Zeilen ist eine Abkapselung eher übertrieben. Grundaufbau der Output-Klasse Die Output-Klasse kann beispielsweise von der Klasse base_stickers abgeleitet werden. Damit erbt sie alle Lademethoden der Elternklasse und kann weitere spezielle Ladefunktionen implementieren und die Ausgabe für die Seitendarstellung aufbereiten. Listing 4.40: Grundaufbau einer Output-Klasse für die Stickers-Anwendung class output_stickers extends base_stickers { 3 4 function initialize(&$data) { 5 $this->data = &$data; 6 } 7 8 function getoutput() { 9 $result = ; 10 if ($stickers = $this->getstickersbycollection($this->data[ collection_id ])) { 11 $result.= <stickers>.lf; 12 foreach ($stickers as $stickerid => $sticker) { 13 $result.= sprintf( <sticker id="%d">%s</sticker>.lf, $stickerid, 14 papaya_strings::getxhtmlstring($sticker[ sticker_text ])); 15 } 16 $result.= </stickers>.lf; 17 } 18 return $result; 19 } 20 } Die Methode output_stickers::getoutput() liefert eine Liste aller Sticker-Einträge einer Sammlung als XML-Dokument zurück. Dabei wird die getstickersbycollection( )-Methode der Klasse base_stickers benutzt. Je nachdem, welche verschiedenen Ausgaben geplant sind, lassen sich verschiedene Anwendungsfälle in unterschiedliche Ausgabemethoden implementieren. Beispielsweise ließe sich eine getrandomoutput()-methode implementieren, um einen Zufallssticker für die Boxenausgabe auszugeben. 130

135 4.1 Eigene Anwendungen schreiben Einbindung der Output-Klasse in Seiten- oder Boxmodule Um die Klasse eines Content-Moduls zu implementieren, instanziieren Sie die Output-Klasse und führen die getoutputmethode() aus: Listing 4.41: Seitenmodul mit output-klasse require_once(papaya_include_path. system/base_content.php ); 3 4 class content_stickers extends base_content { 5 6 var $editfields = array( 7 //... 8 ); 9 10 function getparsedteaser() { 11 // } function getparseddata() { 15 include_once(dirname( FILE ). /output_stickers.php ); 16 $outputobj = &new output_stickers; 17 $outputobj->initialize($this->data); 18 $outputobj->getoutput(); 19 } } Die gesamte Logik für die Ausgabe sowie die Erzeugung der XML-Ausgaben wird nur noch eingebunden und ausgeführt, wenn die Klasse zur Ausgabe verwendet wird, nicht wenn der Seiteninhalt konfiguriert wird Konnektoren - Schnittstellen für andere Anwendungen schaen Wenn Ihre Anwendung Schnittstellen für andere Applikationen in papaya CMS anbieten soll, können Sie dazu eigene Konnektoren benutzen. Für die Beispielanwendung Stickers wird im folgenden vorgestellt, wie eine solche Schnittstelle aussehen kann, über die andere Anwendungen eine Übersicht der Sammlungen oder eine Anzahl Sticker abfragen können, ohne die interne Struktur der Stickers-Anwendung zu kennen. Um eine Konnektorklasse zu erstellen, gehen Sie wie folgt vor: 1. Erstellen Sie eine Klasse connector_stickers, die von base_plugin abgeleitet ist. Eine Konnektorklasse sollte immer den Namenspräfix connector haben: Listing 4.42: Konnektorklasse erstellen 131

136 4 Module für das Backend programmieren 1 require_once(papaya_include_path. base_plugin.php ); 2 3 class connector_stickers extends base_plugin { 4 5 } 2. Erstellen Sie den Konstruktor der Konnektorklasse. Im Konstruktor sollte die Basisklasse mit den Datenbankmethoden eingebunden und als Attribut $this->stickersobj instanziiert werden: Listing 4.43: Konstruktoren der Konnektorklasse 1 function construct() { 2 parent:: construct(); 3 include_once(dirname( FILE ). /base_stickers.php ); 4 $this->stickersobj = &new base_stickers; 5 } 3. Erstellen Sie alle Schnittstellen-Methoden in der Klasse, die sie zur Verfügung stellen wollen. Im folgenden Beispiel sind das die Methoden getcollections(), getstickersbyc ) und getrandomsticker(), die die entsprechenden Methoden auf dem Basisobjekt ausführen: Listing 4.44: Schnittstellenmethoden implementieren 1 function getcollections() { 2 return $this->stickersobj->getcollections(); 3 } 4 5 function getstickersbycollection($collectionid, $limit, $offset) { 6 return $this->stickersobj->getstickersbycollection($collectionid, $limit, $offset); 7 } 8 9 function getrandomsticker($collectionid) { 10 return $this->stickersobj->getrandomsticker($collectionid); 11 } 4. Speichern Sie die Datei ab. Denken Sie daran, dass sich die Namenskonvention auch auf den Dateinamen auswirkt, sodass der Dateiname ebenso wie die Klasse mit dem Präfix connector_ beginnen sollte. 5. Registrieren Sie die Klasse als Konnektor in der modules.xml. Näheres dazu erfahren Sie in Abschnitt 3.4.3, S. 91. Basisklasse anpassen Manchmal ist es notwendig, die Basisklasse zu erweitern, weil der Konnektor zusätzliche Funktionen zur Verfügung stellen soll. Um die Anzahl der Sticker in einer Sammlung beispielsweise für eine seitenweise Darstellung zu ermitteln, können Sie die Basisklasse um entsprechende Funktionen erweitern. Dazu gehen Sie wie folgt vor: 132

137 4.1 Eigene Anwendungen schreiben 1. Erweitern Sie die Methode base_stickers::getstickersbycollection() um das Attribut abscount, in das die komplette Anzahl aller Sticker gespeichert wird. Die Methode connector_stickers::getstickersbycollection() muss also entsprechend erweitert werden: Listing 4.45: Schnittstellenmethode getstickersbycollection() um Zähler erweitern 1 function getstickersbycollection($collectionid, $limit, $offset) { 2 if ($stickers = $this->stickersobj->getstickersbycollection($collectionid, $limit, $offset)) { 3 $this->_stickerscount[$collectionid] = $this->stickersobj->abscount; 4 return $stickers 5 } else { 6 $this->_stickerscount[$collectionid] = 0; 7 } 8 } Wenn die Abfrage erfolgreich war, wird die Anzahl der ausgelesenen Sticker im Attribut $_stickerscount gespeichert. Falls die Abfrage fehlschlägt, wird der Wert des Attributs auf 0 gesetzt (die Sammlung ist leer). 2. Erweitern Sie die Klasse connector_stickers um die Methode getnumberofstickersincollect ): Listing 4.46: Schnittstellenmethode getnumberofstickersincollection() implementieren 1 function getnumberofstickersincollection($collectionid) { 2 if (!isset($this->_stickerscount[$collectionid])) { 3 $this->_stickerscount[$collectionid] = $this->getstickerscount($collectionid); 4 } 5 if (isset($this->_stickerscount[$collectionid])) { 6 return $this->_stickerscount[$collectionid]; 7 } 8 return FALSE; 9 } Wurden bereits Sticker aus der Sammlung mit getstickersbycollection() abgefragt, ist die Anzahl der Sticker im Attribut $_stickerscount abgelegt. Andernfalls ermitteln Sie die Anzahl, indem Sie die Methode base_stickers::getstickerscount( ) aufrufen. 3. Erweitern Sie die Klasse base_stickers um die Methode base_stickers::getstickerscount( ): Listing 4.47: base_stickers um Methode getstickerscount() erweitern 1 function getstickerscount($collectionid) { 2 $sql = "SELECT COUNT(*) AS count 3 FROM %s 4 WHERE collection_id = %d 5 "; 6 $params = array($this->tablesticker, $collectionid); 7 if ($res = $this->databasequeryfmt($sql, $params)) { 8 return $res->fetchfield(); 9 } 10 return FALSE; 11 } 133

138 4 Module für das Backend programmieren Die Methode fragt die Anzahl der Datensätze in der Tabelle papaya_stickers ab, deren collection_id der angegebenen $collectionid entspricht. Die Abfrage liefert nur einen Datensatz und nur ein Feld. Sie können daher die Auswertung der Abfrage vereinfachen, indem Sie statt base_db::fetchrow() und der Rückgabe des Feldwertes mit $row[ count ] die Methode base_db::fetchfield() verwenden. 4. Passen Sie in der Konnektorklasse connector_stickers die Methode getrandomsticker() an. Erweitern Sie die Methoden dazu um den optionalen Parameter $limit: Listing 4.48: Konnektormethode getrandomsticker() anpassen 1 function getrandomsticker($collectionid, $limit = 1) { 2 return $this->stickersobj->getrandomsticker($collectionid, $limit); 3 } 5. Erweitern Sie die Methode base_stickers::getrandomsticker() um den Parameter $limit und passen Sie die Abfrage an: Listing 4.49: Methode getrandomsticker() in base_stickers anpassen 1 function getrandomsticker($collectionid, $limit = 1) { 2 $result = FALSE; 3 4 $randomorder = $this->databasegetsqlsource( RANDOM ); 5 6 $sql = "SELECT s.sticker_id, s.collection_id, s.sticker_text, 7 s.sticker_image, s.sticker_date, s.sticker_author, 8 s.sticker_source, s.sticker_source_url, s.sticker_explanation 9 FROM %s AS s 10 WHERE s.collection_id = %d 11 ORDER BY $randomorder 12 "; $params = array($this->tablesticker, $collectionid); 15 if ($res = $this->databasequeryfmt($sql, $params, (int)$limit)) { 16 return $res->fetchrow(db_fetchmode_assoc); 17 } 18 return $result; 19 } Die Änderungen beschränken sich auf den Parameter $limit mit dem Defaultwert 1. Damit wird die Funktionsweise der Methode zur vorhergehenden Version nicht verändert. Zusätzlich wird die Variable $limit in der Datenbankfunktion base_db:: databasequeryfmt() als dritter Parameter eingesetzt. Da die Auswahl zufällig ist, ist die Angabe des Offsets als vierter Parameter nicht sinnvoll anwendbar. 6. Speichern Sie Ihre Änderungen ab.! Oft kann es sinnvoll sein, eine Basisklasse oder ein Konnektormodul als Singleton zu implementieren. Aus Gründen der Testbarkeit empfiehlt es sich auch, das Registry- Muster (siehe Dependency Injection) anstelle des Singleton-Musters zu benutzen. Um die Komplexität gering zu halten und den Überblick zu erleichtern, wurde hier darauf verzichtet. 134

139 4.2 Widgets für die Benutzeroberfläche einsetzen 4.2 Widgets für die Benutzeroberäche einsetzen Umfangreiche Daten in einem Paging-Control darstellen Wenn Sie immer alle Datensätze in einer Listview anzeigen, kann es schnell dazu führen, dass die Listview und damit die Lade- und Renderzeiten sehr lang werden. Sie können mit papaya CMS verhältnismäßig einfach ein Blättern in Listen realisieren. Das folgende Beispiel stellt vor, wie Sie eine Liste mit einem Paging-Control erweitern können. Dazu wird für die in Abschnitt 4.1, S. 101 erstellte Liste von Stickern ein Paging-Control implementiert. Dadurch werden immer nur eine bestimmte Anzahl Sticker je Seite angezeigt. Um ein Paging-Control zu erstellen, gehen Sie wie folgt vor: 1. Erstellen Sie die Methode, die das XML für das Paging-Control ausgibt: Listing 4.50: XML für Paging-Control ausgeben 1 function getpagingbarxml() { 2 if (isset($this->params[ col_id ])) { 3 include_once(papaya_include_path. system/papaya_paging_buttons.php ); 4 papaya_paging_buttons::getpagingbuttons( 5 $this, 6 NULL, 7 $this->params[ offset_sticker ], 8 $this->params[ limit ], 9 $this->getnumberofstickersincollection($this->params[ col_id ]), 10 9, 11 offset_sticker 12 ); 13 } 14 } Die Methode getpagingbarxml() gibt das Paging-Control nur dann aus, wenn der Parameter col_id gesetzt ist. Ist dies der Fall, wird eine Instanz der Klasse papaya_ paging_buttons erzeugt. 2. Laden Sie für die Paging-Toolbar nur den benötigten Teil der Daten. In der Stickers- Anwendung hat die Methode getstickersbycollection() entsprechende Parameter, die die Anzahl der Einträge sowie den Startpunkt angeben: Listing 4.51: Nur benötigte Daten für eine Seite laden 1 function getstickerslist() { 2 $result = ; 3 if (isset($this->params[ col_id ]) && $this->params[ col_id ] > 0) { 4 $stickers = $this->getstickersbycollection( 5 $this->params[ col_id ], 6 $this->params[ limit ], 7 $this->params[ offset_sticker ]); 8 //... 9 } 135

140 4 Module für das Backend programmieren 10 return $result; 11 } Die Sticker-Einträge werden in der lokalen Variable $stickers gespeichert. Die Angaben für die ID der Sammlung, dem Limit sowie dem Offset werden alle aus dem $ params-array gelesen, um den passenden Abschnitt der Stickerliste aus der Datenbank zu laden. 3. Fügen Sie die XML-Ausgabe der Methode getpagingbarxml() unterhalb des Elements <listview> ein: Listing 4.52: Methode getpagingbarxml() einbinden 1 function getstickerslist() { 2 $result = ; 3 if (isset($this->params[ col_id ]) && $this->params[ col_id ] > 0) { 4 $stickers = $this->getstickersbycollection( 5 $this->params[ col_id ], 6 $this->params[ limit ], 7 $this->params[ offset_sticker ]); 8 $result.= sprintf( <listview title="%s">.lf, 9 papaya_strings::escapehtmlchars($this->_gt( Stickers ))); 10 if (is_array($stickers) && count($stickers) > 0) { 11 // Including the paging bar 12 $result.= $this->getpagingbarxml(); 13 // } else { 15 $result.= sprintf( 16 <status>%s</status>.lf, 17 $this->_gt( No stickers in this collection. )); 18 } 19 $result.= </listview> ; 20 } 21 return $result; 22 } 4. Halten Sie den Status der Paging-Toolbar in der Session fest. Die Parameter sollten in der Methode initialize() gesetzt und initialisiert werden: Listing 4.53: Status der Paging-Toolbar in Session speichern 1 function initialize() { 2 //... 3 $this->initializesessionparam( offset_sticker ); 4 if (empty($this->params[ offset_sticker ])) { 5 $this->params[ offset_sticker ] = 0; 6 } 7 $this->initializesessionparam( limit ); 8 if (empty($this->params[ limit ])) { 9 $this->params[ limit ] = 20; 10 } 11 } Speichern Sie die verwendeten Parameter in der Session, damit sie nicht bei jedem Methodenaufruf mit übergeben werden müssen. Nähere Information zur Verwendung der Session finden Sie in Abschnitt 3.2, S Speichern Sie die Änderungen in den Dateien ab. 136

141 4.2 Widgets für die Benutzeroberfläche einsetzen Details zur Methode papaya_paging_buttons::getpagingbuttons() Die Methode papaya_paging_buttons::getpagingbuttons() hat folgende Methodensignatur: 1 function getpagingbuttons( 2 &$aowner, 3 $baseparams, 4 $offset, 5 $step, 6 $max, 7 $groupcount = 9, 8 $paramname = offset, 9 $buttonalign = NULL) Listing 4.54: Signatur der Methode getpagingbuttons() In der folgenden Tabelle sind alle Parameter der Methode getpagingbuttons() aus der Klasse papaya_paging_buttons aufgeschlüsselt: Parameter &$aowner $baseparams $offset $step $max $groupcount $paramname $buttonalign Tabelle 4.5: Parameter der Methode getpagingbuttons() Bedeutung Basisobjekt Linkparameter Aktueller Offset für die Paginierung Anzahl der Datensätze pro Seite Maximale Anzahl der Datensätze pro Seite Maximale Anzahl der Seitenlinks, die dargestellt werden sollen. Standardwert ist 9. Name des Formularparameters, in dem der Offset-Wert für den aktuellen Abschnitt der Liste (Seite) festgehalten wird. Der Standardwert ist offset. Ausrichtung des Buttons. Standardwert ist NULL. Mögliche Werte sind left, right, default Eingabeformulare mit der Klasse base_dialog erstellen Standardmäßig werden Eingabeformulare für Content-Module automatisch aus den $editfieldoder $editgroup-arrays erzeugt. 137

142 4 Module für das Backend programmieren 4.3 Icons für Bearbeitungsmenü oder Adminanwendung benutzen In diesem Abschnitt erfahren Sie, wie Sie die Standard-Icons für Buttons im Bearbeitungsmenü, Icons oder die Anwendung selbst benutzen können. Sie erfahren auch, wie Sie eigene Icons aus dem Paket in die Benutzeroberfläche einbinden. Wie Standard-Icons im Basissystem integriert sind, siehe Abschnitt 4.3.1, S Standard-Icons aus dem Basissystem benutzen, siehe Abschnitt 4.3.2, S Modulspezifische Icons aus dem Paket benutzen, siehe Abschnitt 4.3.3, S Wie Standard-Icons im Basissystem integriert sind Die Icons des papaya-basissystems sind in der Datei./papaya/inc.glyphs.php registriert. Die globale Variable $PAPAYA_IMAGES ist ein Array, dessen Schlüssel die Bezeichner der Icons bilden. Die Bezeichner setzen sich dabei aus dem Namen der Gruppe und des Icons zusammen, die durch einen Bindestrich miteinander verbunden sind. Das Array $PAPAYA_IMAGES enthält dabei den physischen Dateinamen als Wert. In./papaya/module.php wird der Instanz des eigenen Backend-Moduls eine Referenz auf $PAPAYA_IMAGES als $images-attribut gesetzt. Bei Bedarf kann das Attribut an Unterklassen als Referenz weitergegeben werden: 1 $myobj->images = &$this->images; Listing 4.55: Referenz auf $images-array weitergeben Vorhandene Icons aus dem Basissystem referenzieren Übersicht der Standard-Icons papaya CMS bietet im Backend eine Übersichtsseite mit den Icons des Basissystems. Sie finden die Übersichtsseite im Bereich Einstellungen, wenn Sie auf den Menüpunkt Icons ansehen klicken: 138

143 4.3 Icons für Bearbeitungsmenü oder Adminanwendung benutzen Abbildung 4.2: Beispiel für eine Icon-Gruppe Die Tabellenüberschrift bezeichnet die Gruppe. In den Tabellenzellen wird jeweils ein Icon angezeigt und sein Name sowie die verfügbaren Größen angegeben. Icons in Anwendungen benutzen! Bitte verwenden Sie Icons gemäß ihrer Bedeutung, nicht ihres Aussehens. Um die Auswahl zu erleichtern, sind die Icons nach verschiedenen Themen in Gruppen sortiert: actions categories items places status Icons, die für eine bestimmte Funktion stehen, finden Sie demnach in der Icongruppe actions. Sie binden Icons in die Anwendung ein, indem Sie einen Bezeichner aus dem Gruppennamen und dem Iconnamen zusammenstellen. Den Bezeichner setzen Sie als Index für das Array $this->images ein. Das Array $this->images enthält alle Icons des Systems als absolute URLs und ist standardmäßig in allen Modulen enthalten, die Backendausgaben besitzen. Der zu verwendende Bezeichner setzt sich aus dem Gruppennamen und dem Iconnamen zusammen. Die Namen werden mit Bindestrichen miteinander verbunden werden. Aus places und network-server wird also places-network-server. Icons lassen sich dabei wie folgt beispielsweise für die XML-Ausgabe von Listitems referenzieren: $result.= sprintf( 3 <listitem image="%s" title="%s">.lf, 4 $this->images[ places-network-server ], 5 $title); 6... Listing 4.56: Icons in die Backendausgabe einfügen 139

144 4 Module für das Backend programmieren Icons in base_btnbuilder benutzen Wenn Sie eine Toolbar mit einer Instanz der Klasse base_btnbuilder erstellen, müssen Sie der Klasse eine Referenz auf das $images-array übergeben: 1 $this->menubar = &new base_btnbuilder; 2 $this->menubar->images = &$this->images; Listing 4.57: Referenz auf $images-array übergeben Anschließend können Sie über die Methode addbutton() der base_btnbuilder- Klasse die Toolbar mit Buttons bestücken. Der dritte Parameter bezeichnet das Icon, das verwendet werden soll (falls gewünscht). Es ist hier nicht nötig auf $this->images zurückzugreifen. Das wird von base_btnbuilder selbständig erledigt Eigene Icons aus dem Paket referenzieren Für eigene Anwendungen ist es manchmal wünschenswert, spezielle Icons zu verwenden, die nicht im Basissystem enthalten sind. Um solche Icons zu verwenden muss lediglich die Quellenangabe des Icons etwas anders aussehen als für Icons im Basissystem (siehe Abschnitt 4.3.2, S. 138). Die Angabe für das Bild setzt sich aus dem Schlüsselwort module:, der GUID des Moduls sowie der relativen Pfadangabe zur Icon-Datei (./pics/icon.png) zusammen: Listing 4.58: Beispielausgabe für die Iconreferenz 1 <glyph src="module: abcdef abcdef/pics/my_icon.png" /> 2 <listitem image="module: abcdef abcdef/pics/my_other_icon.gif" /> Da es nicht besonders einfach ist, den Pfad zusammenzustellen, steht in der Klasse base_ module die Methode geticonuri() zur Verfügung. Sie brauchen dieser Klasse lediglich den relativen Pfad zur Bilddatei zu übergeben. Die vollständige URL wird durch die Methode erzeugt. Die Stickers-Klasse admin_stickers erhält beispielsweise bei ihrer Instanziierung eine Referenz auf die edmodule_stickers-instanz. Die Klasse edmodule_stickers wiederum erweitert die Klasse base_module, in der die Methode geticonuri() implementiert ist. Im folgenden Beispiel wird dargestellt, wie mit dieser Methode das Icon eines Pakets eingebunden wird: Listing 4.59: Icon-URL mit base_module::geticonuri() erzeugen $result.= sprintf( <glyph src="%s" />.LF, 140

145 4.4 Phrasen übersetzen 3 $this->parentobj->geticonuri( pics/icon.png )); 4... Die Icons selbst werden im Unterverzeichnis./pics/16x16/,./pics/22x22/ sowie./pics/48x48/ abgelegt. papaya CMS findet das Bild automatisch im Ordner mit der entsprechenden Größenangabe. 4.4 Phrasen übersetzen Phrasen sind Texte für Feldbeschriftungen, Dialogmeldungen, Titel für Abschnitte, Tabellenspalten und Buttons. Während bestimmte Texte automatisch übersetzt werden, müssen Sie in anderen Fällen explizit Übersetzungsmethoden aus der Klasse base_object ausführen. Die Klasse base_object stellt zu diesem Zweck folgende Methoden zur Verfügung: $this->_gt($phrase, $module), um eine Phrasen zu übersetzen, siehe Abschnitt 4.4.1, S $this->_gtf($phrase, $vals, $module), um eine Phrase mit Platzhaltern zu übersetzen, siehe Abschnitt 4.4.2, S $this->_gtfile($filename), um einen längeren Textabschnitt im Backend sprachabhängig auszugeben, siehe Abschnitt 4.4.3, S Sprachkonventionen bei der Eingabe von Phrasen beachten Wenn Sie Phrasen eingeben, sollten Sie einige wesentliche Regeln beachten: Standardsprache ist American English. Bei fehlender Übersetzung wird die Phrase aus dem Quelltext genommen. Sie sollten die Phrasen daher nicht in einer anderen Sprache eingeben, da es andernfalls zu Ausgaben mit gemischten Sprachen kommen kann. Setzen Sie niemals Phrasen aus anderen Phrasen zusammen, wie dies im flogenden Beispiel gemacht wurde: Listing 4.60: Schlechtes Beispiel für Phrasenübersetzung 1 $this->label = sprintf( 2 $this->_gt( %s has been changed. ), 3 $this->_gt( Category ) 4 ); 141

146 4 Module für das Backend programmieren Beide Phrasen werden getrennt voneinander übersetzt und anschließend mit sprintf( ) verknüpft. Bei Übersetzungen kann es in bestimmten Sprachen zu Problemen kommen, da bei der getrennten Übersetzung die grammatischen Relationen nicht beachtet werden können. Das obige Beispiel für eine Phrasenübersetzung kann wie folgt verbessert werden: 1 $this->label = $this->_gt( 2 Category hs been changed. 3 ); Listing 4.61: Gutes Beispiel für Phrasenübersetzung $this->_gt() benutzen Wenn Sie eine einfache Phrase für die Benutzeroberfläche im Backend übersetzen möchten, können Sie die Methode $this->_gt() benutzen. gt steht für get text und ist ein einfacher Phrasenübersetzer. Das folgende Listing stellt die Signatur der _gt()-methode vor: Listing 4.62: Signatur der Methode base_object::_gt() 1 function _gt($phrase, $module = NULL) { } Der Parameter $phrase enthält den zu übersetzenden Text in englischer Sprache. Der zweite Parameter $module ist optional und enthält den Modulnamen. Wird kein Modulname angegeben, wird der Scriptname unterhalb von./papaya/ verwendet. Im folgenden Listing wird dargestellt, wie Sie die Methode _gt() benutzen können: Listing 4.63: Phrase mit $this->_gt() übersetzen $this->addmsg(msg_warning, $this->_gt( Please enter search criteria. )); 3... Im obigen Beispiel wird die Phrase eines Warndialogs übersetzt. Dabei wird die Ausgabe von $this->_gt() direkt für den zweiten Parameter der Methode $this->addmsg( ) verwendet $this->_gtf() benutzen Wenn Sie einen Text mit Platzhaltern im Backend sprachabhängig ausgeben möchten, können Sie die Methode $this->_gtf() benutzen. gtf steht für get text formatted und 142

147 4.4 Phrasen übersetzen funktioniert im Prinzip wie _gt(). Der Unterschied besteht darin, dass die Methode so ähnlich wie sprintf() funktioniert. Das folgende Listing stellt die Signatur der Methode base_object::_gtf() vor: Listing 4.64: Signatur der Methode base_object::_gtf() 1 function _gtf($phrase, $vals, $module = NULL) { } Der erste Parameter $phrase enthält den zu übersetzenden Text in englischer Sprache. Der Text enthält Platzhalter, wie sie auch in der klassischen C-Funktion sprintf() benutzt werden (beispielsweise %s oder %d). Der zweite Parameter $vals ist ein Array mit den Werten, die anstelle der Platzhalter in den String hineinformatiert werden sollen. Der dritte Parameter $module ist optional und enthält den Modulnamen. Wird kein Modulname angegeben, wird der Scriptname unterhalb von./papaya/ verwendet. Das folgende Listing stellt dar, wie mit der Methode $this->_gtf() eine Phrase übersetzt wird: Listing 4.65: Phrase mit $this->_gtf() übersetzen $msg = $this->_gtf( 3 Do you really want to delete collection "%s" #%d?, 4 array( 5 $this->collections[$this->params[ col_id ]][ collection_title ], 6 $this->params[ col_id ] 7 ) 8 ); 9 $this->dialog = &new base_msgdialog($this, $this->paramname, $hidden, $msg, 10 warning ); Mit der Methode $this->_gtf() wird der Text eines Fragedialogs übersetzt. Als zweiter Parameter wird ein Array übergeben, das die Werte für den String- und den Dezimalplatzhalter in der Phrase enthält. Anschließend wird eine Instanz der Klasse base_msgdialog mit der übersetzten Phrase angelegt, die in der Variablen $msg gespeichert worden ist $this->_gtfile() benutzen Wenn Sie einen längeren Text im Backend sprachabhängig ausgeben möchten, können Sie die Methode $this->_gtfile() benutzen. Diese Methode liest Textdateien ein, die im sprachspezifischen Verzeichnis innerhalb des papaya-verzeichnisses gespeichert sind. Listing 4.66: Signatur der Methode base_object::_gtfile() 1 function _gtfile($filename){ } 143

148 4 Module für das Backend programmieren Der Parameter $filename enthält den Namen der Datei, die sich im Verzeichnis PAPAYA_ PATH_WEB.PAPAYA_PATH_ADMIN. /data/.iso-lng befindet. Beispielsweise ist die Datei sitemap_info.txt bei aktivierter deutscher Backendsprache unter folgendem Pfad zu finden: Listing 4.67: Beispielpfad für die Datei sitemap_info.txt 1./papaya/data/de-DE/sitemap_info.txt! Texte sollten mindestens in Deutsch und Englisch vorliegen. Wenn ein Text nicht in der aktuell ausgewählten Backendsprache vorliegt, wird kein Ersatztext dargestellt. Die Methode _gtfile() wird wie folgt aufgerufen: Listing 4.68: Sprachspezifische Textdatei mit $this->_gtfile() einbinden 1 $this->layout->addright( 2 sprintf( 3 <sheet width="350" align="center">. 4 <text><div style="padding: 0px 5px 0px 5px; ">. 5 %s</div></text></sheet>, 6 $this->_gtfile( linkdb_info.txt ) 7 ); Sie müssen lediglich den Namen der Textdatei angeben. Der Pfad bis zur Datei wird durch die Implementation der Methode automatisch ergänzt. 144

149 5 Fehlersuche in papaya CMS papaya CMS enthält zahlreiche Erweiterungen, die die Suche nach Fehlern im Programmcode von PHP oder XSLT erleichtern. PHP- und SQL-Fehler können abgefangen und in einem einheitlichen Format in der Firefox-Erweiterung Firebug oder im Browser als HTML ausgeben werden. Mit base_object::debug() lässt sich gezielt der Inhalt von Variablen und Objekten inspizieren. 5.1 Konguration der Fehlerausgabe Im Abschnitt Fehlersuche der Konfiguration können Sie einstellen, welche Fehler ausgegeben werden und wie die Ausgabe erfolgen soll. Die vollständige Liste von Konfigurationsoptionen finden Sie in papaya CMS 5: Handbuch für Administratoren, Abschnitt PAPAYA_DBG_SHOW_DEBUGS Tabelle 5.1: Wichtige Konfigurationsoptionen zur Fehlersuche PAPAYA_DBG_PHP_SHOW_ERROR Bestimmt, ob Aufrufe von base_object::debug() eine Ausgabe erzeugen sollen oder nicht. Auf Produktionsinstallationen sollte diese Option aus Sicherheitsgründen per define() in der conf.inc.php deaktiviert werden. Bestimmt, ob Fehlermeldungen ausgegeben werden oder nicht. Auf Produktionsinstallationen sollte diese Option aus Sicherheitsgründen per define() in der conf.inc.php deaktiviert werden. PAPAYA_DBG_PHP_SHOW_FIREBUG Bestimmt, ob die Ausgabe von Fehlermeldungen und debug()-aufrufen in der Konsole der Firebug-Erweiterung erfolgen soll oder im Browser. 145

150 5 Fehlersuche in papaya CMS Tabelle 5.1: Wichtige Konfigurationsoptionen zur Fehlersuche (forts.) PAPAYA_DBG_PHP_ERROR Bestimmt, welcher Fehlerlevel zum Einsatz kommen soll. Im Entwicklungsumfeld sollte dieser auf E_ALL stehen, im Produktivbetrieb können z.b. Notices ausgeschaltet werden. In der Regel werden Notices während der Entwicklung beseitigt. Dennoch können auch in Produktivumgebungen sehr viele Notice-Meldungen das Protokoll von papaya CMS überfluten, sodass schwerwiegendere Fehlermeldungen leicht übersehen werden können. 5.2 Variablen mit base_object::debug() inspizieren Sie können die Methode base_object::debug() mit beliebig vielen Parametern aufrufen. Wird kein Parameter übergeben, besteht die Ausgabe lediglich aus dem Backtrace (sofern aktiviert) und dem Speicherverbrauch sowie der Zeit seit dem letzten debug() -Aufruf. Sie können Strings und Zahlen übergeben, Variablen oder Objekte. Die meisten Klassen, die Sie schreiben, sind indirekt von base_object abgeleitet. Daher können Sie debug() einfach auf dem aktuellen Objekt mit $this->debug() aufrufen. debug() lässt sich aber auch als Klassenmethode von base_object mit base_object::debug( ) aufrufen. Listing 5.1: Beispielaufrufe von base_object::debug() $this->debug(); 3 $this->debug(1); 4 base_object::debug( test, 1); 5 $this->debug($this, $var, blah ); 6... Der folgende Screenshot stellt die Ausgabe der Debugaufrufe aus dem obigen Listing dar: 146

151 5.2 Variablen mit base_object::debug() inspizieren Abbildung 5.1: Beispiel einer Ausgabe mit base_object::debug() Das Backtrace enthält auch die Zeilenangaben. Das macht es leicht den Programmablauf nachzuvollziehen. Die Angaben Memory Diff und Time Diff beziehen sich auf den jeweils vorhergegangenen debug()-aufruf. Werden mehrere Parameter übergeben, wer- 147

152 5 Fehlersuche in papaya CMS den Sie direkt nacheinander ausgegeben und das Backtrace wird nur einmal ausgegeben. Die Ausgabe von Objekten ist üblicherweise sehr lang. In dem Beispiel sehen Sie auch, warum es so wichtig ist, die Debugausgabe auf Livesystemen abzuschalten. Datenbank- Zugangsdaten und Informationen über die Pfadstruktur können ausgegeben werden, sodass potentielle Angreifer ohne viel Aufwand wichtige Informationen über das System erhalten würden. 5.3 Meldungen mit base_object::logmsg() protokollieren Dieser Abschnitt erklärt, wie Sie mit base_object::logmsg() wertvolle Debug-Informationen auf einer live-webseite sammeln können. Die Protokollfunktion sollte aus folgenden Gründen benutzt werden: Sie können detaillierte Informationen sammeln, um Fehler aufzuspüren. Dies ist wichtig, wenn Sie auf einem Livesystem kein normales Debugging verwenden können. Sie können Aktionen nachvollziehen, die im System stattgefunden haben. Sie können die Nachrichten danach filtern, wie schwerwiegend sie sind und in welchem Systembereich sie auftreten. Da logmsg() in base_object implementiert ist, steht sie in allen Klassen im papaya- Basissystem zur Verfügung Funktionsweise von base_object::logmsg() Die Methode logmsg() ist in der Klasse base_object implementiert. logmsg() verwendet seinerseits eine globale Instanz von base_log um die Daten in die Datenbank zu schreiben. Diese Funktion kann von Jeder Klasse genutzt werden, die von base_object abgeleitet ist. Klassen, die nicht von base_object abstammen, können die Methode logmsg() statisch aufrufen (base_object::logmsg()). Das folgende Listing stellt vor, wie Sie logmsg() aufrufen können: 1 $this->logmsg( 2 $msglevel, Listing 5.2: Aufruf der Methode logmsg() 148

153 5.3 Meldungen mit base_object::logmsg() protokollieren 3 $msgtype, 4 $overviewmsg, 5 $detailmsg, 6 $addbacktrace, 7 $backtraceoffset); Die Methode logmsg() verfügt über folgende Parameter: Log-Level Tabelle 5.2: Parameter der Methode logmsg() Bedeutung $msglevel Grad der Fehlermeldung, siehe Tabelle 5.3, S $msgtype $overviewmsg $detailmsg $addbacktrace $backtraceoffset Dieser Parameter beschreibt den Nachrichtentyp, siehe Tabelle 5.4, S Kurzversion der Nachricht. Dieser Text erscheint in der Übersichtsliste im Protokoll. Ausführliche Nachricht. Dieser Text enthält alle Informationen, um den Fehler zu identifizieren oder die Nachricht möglichst informativ zu gestalten. TRUE, wenn die Log-Nachricht ein Backtrace der Funktionsaufrufe erhalten soll, andernfalls FALSE. Integer-Wert, der den Offset im Backtrace angibt. Damit der Aufruf von logmsg() selbst nicht im Backtrace erscheint, kann ein Offset angegeben werden. Standard ist 2. Fehler-Level Die Fehler-Level sind in sys_error.php definiert und im Prinzip selbsterklärend. In der folgenden Tabelle werden sie aufgeschlüsselt: Log-Level MSG_INFO MSG_WARNING Tabelle 5.3: Fehlerebenen für Nachrichten im Systemprotokoll Bedeutung Einfache Infomeldungen werden in diesem Level protokolliert. In diesem Level werden Warnmeldungen protokolliert, die auf potentielle Probleme wie eine falsche Konfiguration oder fehlende Daten hinweisen. 149

154 5 Fehlersuche in papaya CMS Log-Level MSG_ERROR Tabelle 5.3: Fehlerebenen für Nachrichten im Systemprotokoll (forts.) Bedeutung Eindeutige Fehler wie Query-Fehler in der Datenbank oder sonstige Inkonsistenzen werden in diesem Level protokolliert. Nachrichtentypen Die Nachrichtentypen sind in der Datei sys_base_object.php definiert. Die folgende Tabelle schlüsselt alle Nachrichtentypen auf: Log-Level PAPAYA_LOGTYPE_USER PAPAYA_LOGTYPE_PAGES Tabelle 5.4: Nachrichtentypen aus base_object Bedeutung Logging von Benutzer-Ereignissen, beispielsweise Login oder Logout. Logging von Seiten-Ereignissen, beispielsweise Veröffentlichen oder Privatstellen von Seiten. PAPAYA_LOGTYPE_DATABASE Logging von Datenbankfehlern, beispielsweise Query-Fehler durch fehlerhaftes SQL. PAPAYA_LOGTYPE_CALENDAR PAPAYA_LOGTYPE_CRONJOBS PAPAYA_LOGTYPE_SURFER PAPAYA_LOGTYPE_SYSTEM PAPAYA_LOGTYPE_MODULES Logging für Kalender-Meldungen. Logging für papaya-cronjobs. Logging für Surfer und Community-Ereignisse, beispielsweise Login oder Logout. Fehler in einer Klasse des Basissystems. Fehler in eigenen Modulen base_object::logmsg() benutzen Sie können logmsg() benutzen, um alle möglichen Arten von Informationen zu protokollieren. Beispielsweise könnten Sie in der Anwendung eines Warenwirtschaftssystems eine Warnmeldung in das Systemprotokoll schreiben, wenn die Anzahl der Waren unter einen bestimmten Wert fallen oder wenn alle Waren eines bestimmten Typs ausverkauft sind: Listing 5.3: logmsg() benutzen 150

155 5.3 Meldungen mit base_object::logmsg() protokollieren 1 function getshelfcontentxml() { 2 $result = ; 3 $shelf = $this->loadshelfdata(); 4 if (isset($shelf) && is_array($shelf) && count($shelf) > 0) { 5 $result.= <shelf> ; 6 foreach ($shelf as $product => $count) { 7 $result.= sprintf( <product name="%s" count="%s" />.LF, 8 papaya_strings::escapehtmlchars($product), 9 papaya_strings::escapehtmlchars($count)); 10 if ($count = 0) { 11 $this->logmsg(msg_warning, MSG_LOGTYPE_MODULES, 12 sprintf($this->_gt( No products in stock: "%s"! ), $product), 13 sprintf($this->_gt( You don t have any "%s"s. Order new products quickly! ), $product)); 14 } elseif ($count <= 10) { 15 $this->logmsg(msg_info, MSG_LOGTYPE_MODULES, 16 sprintf($this->_gt( Low amount of products in stock: "%s". ), $product), 17 sprintf($this->_gt( You will soon run out of "%s"s. Please order new products. ), $product)); 18 } 19 } 20 $result.= </shelf> ; 21 } 22 } Mit $this->loadshelfdata() werden die Daten aus der Datenbank geladen. Die Implementation dieser Funktion ist in diesem Tutorial nicht so wichtig. Der Rückgabewert der Funktion ist ein assoziatives Array von Warennamen als Schlüssel und ihrer Anzahl als Wert. Wenn diese Funktion ein Array zurückgibt, wird mit der foreach-schleife durch die Array- Elemente iteriert. Nach der XML-Ausgabe der Einträge wird überprüft, ob überhaupt noch Waren dieses Typs im Lager sind: Listing 5.4: Warnmeldung in Protokoll eintragen 1 if ($count = 0) { 2 $this->logmsg(msg_warning, MSG_LOGTYPE_MODULES, 3 sprintf($this->_gt( No products in stock: "%s"! ), 4 $product), 5 sprintf($this->_gt( You don t have any "%s"s. Order new products quickly! ), 6 $product)); Wenn nicht, wird eine Warnung ausgelöst, die in das Systemprotokoll geschrieben wird. Die Warnung hat die Gewichtung MSG_WARNING und den Typ MSG_LOGTYPE_MODULES. Mit $this->_gt() wird eine Übersetzung für den angegebenen Text aus dem papaya-phrasensystem geholt. Wenn weniger als zehn Stück der vorliegenden Ware im Regal vorhanden sind, wird eine Hinweismeldung in das Protokoll geschrieben: Listing 5.5: Infomeldung in Protokoll eintragen 1 } elseif ($count <= 10) { 2 $this->logmsg(msg_info, MSG_LOGTYPE_MODULES, 3 sprintf($this->_gt( Low amount of products in stock: "%s". ), $product), 4 sprintf($this->_gt( You will soon run out of "%s"s. Please order new products. ), $product) 5 ); 151

156 5 Fehlersuche in papaya CMS In diesem Fall wird MSG_INFO statt MSG_WARNING verwendet. In der Nachrichtenübersicht des Systemprotokolls wird ein anderes Symbol dargestellt. Durch die unterschiedliche Gewichtung können Sie Nachrichten nach bestimmten Leveln filtern. Näheres dazu erfahren Sie in papaya CMS 5: Handbuch für Administratoren, Kapitel Mit base_object::addmsg() Nachrichten an Benutzer ausgeben Dieser Abschnitt erklärt, wie Sie mit base_object::addmsg() Benachrichtigungen an Benutzer ausgeben können. Die Nachricht wird im Content-Bereich der Seite als Dialog angezeigt. Das folgende Listing stellt vor, wie die Funktion aufgerufen wird: Listing 5.6: Nachrichten an Benutzer ausgeben 1 $this->addmsg( 2 MSG_INFO, 3 sprintf($this->_gt( Added new product "%s". ), $this->params[ product_name ]) 4 ); Der erste Parameter ist einer der bekannten Nachrichtenlevel, siehe Tabelle 5.3, S Der zweite Parameter erhält den Nachrichtentext, der mit $this->_gt() in die aktuelle Content-Sprache des Backends übersetzt wird. Meldung zusätzlich im Fehlerprotokoll protokollieren Wenn Sie die Nachricht zusätzlich noch ins Systemprotokoll eintragen möchten, müssen Sie zwei weitere Parameter anfügen: Listing 5.7: Benutzer-Nachrichten zusätzlich ins Systemprotokoll schreiben 1 $this->addmsg( 2 MSG_INFO, 3 sprintf($this->_gt( Added new product "%s". ), $this->params[ product_name ]), 4 TRUE, 5 PAPAYA_LOGTYPE_MODULES 6 ); Der dritte Parameter, standardmäßig FALSE, bestimmt, ob die Nachricht auch in das Systemprotokoll geschrieben werden soll. Dazu müssen Sie also TRUE übergeben. 152

157 5.5 Fehlersuche mit base_object::logvariable() Details zur Methode base_object::addmsg() Die Methode base_object::addmsg() ist mit folgenden Parametern definiert: Listing 5.8: Methodensignatur von base_object::addmsg() 1 function addmsg($level, $text, $log = FALSE, $type = PAPAYA_LOGTYPE_SYSTEM) { } Parameter Tabelle 5.5: Parameter der Methode addmsg() Bedeutung $level Fehlerebene, siehe Tabelle 5.3, S $text $log Text der Meldung. Gegen Sie nicht direkt den Text der Meldung ein, sondern übersetzen Sie diesen mit $this- >_gt(). TRUE, wenn die Nachricht auch in das Systemprotokoll geschrieben werden soll, andernfalls FALSE (Standardeinstellung). $type Auswahl eines Nachrichtentyps, siehe Tabelle 5.4, S Standard ist PAPAYA_LOGTYPE_SYSTEM. 5.5 Fehlersuche mit base_object::logvariable() Dieser Abschnitt erklärt, wie Sie mit base_object::logvariable() die Inhalte einer Variablen in das Systemprotokoll schreiben können. In bestimmten Fällen lassen sich dadurch wertvolle Debug-Informationen auf einer live-webseite sammeln. Die Funktion base_object::logvariable() sollte aus folgenden Gründen benutzt werden: Wenn Sie sporadisch auftretende Fehler suchen und die Inhalte einer Variable während des laufenden Betriebs überwachen wollen. Wenn Sie auf dem System die Debugausgabe nicht benutzen wollen und deshalb nicht die Methode $this->debug() verwenden können. Wenn Sie den Nutzern die Debugausgabe nicht zeigen wollen. Da base_object::logvariable() in base_object implementiert worden ist, steht sie in allen Klassen im papaya-basissystem zur Verfügung. 153

158 5 Fehlersuche in papaya CMS Funktionsweise von base_object::logvariable() Das folgende Listing stellt die Signatur der base_object::logvariable()-methode vor: Listing 5.9: Signatur der Methode base_object::logmsg() 1 function logvariable($level, $type, $title, $variable, $addbacktrace = FALSE, $backtraceoffset = 3) { } Die Funktion base_object::logvariable() verfügt über folgende Parameter: Log-Level Tabelle 5.6: Parameter der Methode base_object::logmsg() Bedeutung $level Grad der Fehlermeldung, siehe Tabelle 5.3, S $type $title $variable $addbacktrace $backtraceoffset Dieser Parameter beschreibt den Nachrichtentyp, siehe Tabelle 5.4, S Titel der Variablenausgabe. Dieser Text erscheint in der Übersichtsliste im Protokoll. Referenz zur Variablen, deren Inhalt in das Protokoll geschrieben werden soll. TRUE, wenn die Log-Nachricht ein Backtrace der Funktionsaufrufe erhalten soll, andernfalls FALSE (Standardeinstellung). Integer-Wert, der den Offset im Backtrace angibt. Damit der Aufruf von base_object::logmsg() selbst nicht im Backtrace erscheint, kann ein Offset angegeben werden. Standard ist base_object::logvariable() benutzen Im folgenden Beispielprogramm wird der Inhalt einer Variablen durch base_object: :logvariable() protokolliert. Denkbar wäre der Fall, in dem der Aufruf der Funktion fehlschlägt, mit der die Inhalte einer Variablen in die Datenbank geschrieben werden. Um den Zustand der Variablen näher zu untersuchen, kann man ihren Inhalt in das Systemprotokoll schreiben: Listing 5.10: Variable protokollieren 154

159 5.6 Datenbankzugriffe optimieren $dataset = $this->createfromxml($myxmlvar); 3 if (!$this->updaterecord($dataset)) { 4 $this->logvariable( 5 MSG_ERROR, 6 MSG_LOGTYPE_MODULES, 7 "example_class::updaterecord() failed", 8 $dataset, 9 TRUE, ); 12 } Datenbankzugrie optimieren Optimierte Datenbankabfragen können die Performance spürbar verbessern. Mit papaya CMS können Sie eine SQL-Abfrage anzeigen und durch ein Explain analysieren lassen. Explain ist eine Funktion des SQL-Datenbankservers, der die Zugriffsstrategie des Servers für eine mit Explain gekennzeichnete SQL-Abfrage ausgibt. Die Implementation ist dabei von Server zu Server unterschiedlich, weshalb diese Funktion in papaya CMS durch die Datenbankabstraktion ausgeführt wird. Ferner können Sie sich die Anzahl der SQL-Abfragen bei einem Seitenaufruf anzeigen lassen und langsame Abfragen für die spätere Analyse protokollieren. Wenn Sie die Konfigurationsoption PAPAYA_DBG_DATABASE_EXPLAIN aktivieren, wird für alle Datenbankabfragen der Explain-Modus aktiviert. Die Ausgabe ist oft sehr lang, doch auch aufschlussreich. Sie sehen beispielsweise, welche Querys bei einer Seitenerstellung lange dauern und können dort ansetzen, die Abfrage mittels Umstellung oder durch Verwendung von Indices zu beschleunigen Abfragen mit base_db::databasedebugnextquery() analysieren. Nahezu alle Abfragen sind dynamisch und verwenden Platzhalter um kontextabhängige Parameter in die Abfrage einzubringen. Es ist daher nicht möglich eine Abfrage einfach aus dem Quelltext herauszukopieren. Um SQL-Abfragen auszugeben, können Sie die Methode base_db::databasedebugnextquery() benutzen. Führen Sie diese Methode aus, bevor Sie beispielsweise mit base_db::databasequeryfmt() eine Abfrage ausführen. Wenn Sie mehrere aufeinanderfolgende Abfragen analysieren möchten, können Sie als Parameter die Zahl der auszugebenden Abfragen angeben. Beispielsweise gibt der Aufruf von databasequeryfmt(3) die drei nächsten ausgeführten Abfragen aus, unabhängig 155

160 5 Fehlersuche in papaya CMS von ihrem Klassen-Kontext. Wenn Sie keinen Parameter übergeben, wird nur die nächste Abfrage ausgegeben. Im folgenden Screenshot wird die Ausgabe einer Debugmeldung mit databasedebugnext- Query() dargestellt: Abbildung 5.2: Beispiel einer Ausgabe mit base_db::databasedebugnextquery() In der linken oberen Seite der Ausgabe wird der Name der Klasse dargestellt, die den Aufruf ausgelöst hat. Ferner enthält dieses Feld noch die Nummer der Query und gibt den Verbindungstyp aus. Im obigen Beispiel handelt es sich um eine Leseverbindung ( read connection ) In der oberen rechten Seite der Ausgabe steht der Zeitbedarf der Abfrage und in Klammern die Gesamtdauer aller ausgegebenen Abfragen. Anschließend wird die komplette SQL-Abfrage angezeigt. Direkt unterhalb der SQL-Codeausgabe wird ausgegeben, wieviele Datensätze von wievielen möglichen geholt wurden. Es folgt die Ausgabe der EXPLAIN-Query und ganz unten das Backtrace Langsame SQL-Abfragen protokollieren In papaya CMS gibt es die Möglichkeit, langsame SQL-Abfragen zu protokollieren. Welche SQL-Abfragen langsam sind, können Sie dabei selber festlegen. Zu diesem Zweck geben Sie eine maximale Abfragezeit als Grenzwert an. 156

161 Teil II Referenz 157

162

163 6 Backend-Komponenten Ob Listen, Werkzeugleisten, Formulare oder Informationen; das Backend von papaya versteht eine Reihe von Ausgabekomponenten. Ebenso wie für die Frontend-Ausgabe wird XML via XSLT zu HTML transformiert, folglich müssen wir XML zusammenbasteln um eine Ausgabe zu erzeugen. Wie ein Administrationsmodul aufgebaut ist und wie es in papaya CMS verfügbar gemacht wird, erfahren Sie in Kapitel 4, S In diesem Kapitel geht es ausschließlich um die XML-Ausgabe und der Art und Weise, wie papaya CMS die grafische Darstellung daraus generiert. 6.1 Übersicht über die verfügbaren Komponenten Grundlegende Hinweise Um die XML-Ausgabe des Backends anzusehen, hängen Sie?XML=1 (bzw. &XML=1) an die URL an.! Inhalte in Attribut-Knoten mit papaya_strings::escapehtmlchars() maskieren Template-Parameter Die Parameter werden an unterschiedlichen Stellen konfiguriert. Teilweise kommen die Informationen aus der conf.inc.php, teilweise aus den papaya-einstellungen. Tabelle 6.1: Parameter im Template des papaya-backends Parameter Bedeutung COLUMNWIDTH_CENTER Bestimmt die Breite der mittleren Inhaltsspalte COLUMNWIDTH_LEFT Bestimmt die Breite der linken Inhaltsspalte 159

164 6 Backend-Komponenten Parameter COLUMNWIDTH_RIGHT PAGE_BASE_URL PAGE_ICON PAGE_LANGUAGE PAGE_MODE PAGE_PATH_SKIN PAGE_PROJECT PAGE_SELF PAGE_TITLE PAGE_TODAY PAGE_URL PAGE_USER PAGE_WEB_PATH Tabelle 6.1: Parameter im Template des papaya-backends (forts.) PAPAYA_DBG_DEVMODE PAPAYA_LOGINPAGE PAPAYA_UI_LANGUAGE Bedeutung Bestimmt die Breite der rechten Inhaltsspalte Basis-URL des Backends, im Normalfall /papaya, könnte aber auch /my-cms/admin oder anders lauten. Icon des aktuellen Bereiches / der aktuellen Anwendung. Bei Anwendungen wird automatisch die 22x22px Version des in der modules.xml angegebenen Icons verwendet. Kürzel der aktuell verwendeten Sprache, z.b. de-de. Bestimmt, ob die Ausgabe ein Frameset, ein Frame oder eine normale Seite ist (wird beim MediaDB- Browser verwendet). Pfad zum Papaya Skin, default ist skins/default. Enthält den Namen des Projektes, wie es unter Einstellungen benannt wurde. Enthält den Scriptnamen, also z.b. mediadb.php Titel des aktuellen Breiches / der aktuellen Anwendung. Aktuelles Datum/Uhrzeit Komplette URL zur aktuellen Seite Aktuell angemeldeter Benutzer Enthält den Pfad zur Ausgabe von papaya, also wo die /index.php liegt Ob der Debugmodus angeschaltet ist oder nicht. Darüber kann man Debugausgaben im Template steuern. Ist true, wenn die Loginseite ausgegeben wird. Aktuell eingestellte Sprache für das Backend. PAPAYA_USE_JS_WRAPPER Ob JavaScript zusammengefasst werden soll (default = true) PAPAYA_USE_JS_GZIP Ob JavaScript komprimiert werden soll (default = true) PAPAYA_USE_OVERLIB Ob die overlib für hints verwendet werden soll. (default = true) 160

165 6.1 Übersicht über die verfügbaren Komponenten Parameter PAPAYA_USE_RICHTEXT Tabelle 6.1: Parameter im Template des papaya-backends (forts.) PAPAYA_USE_RICHTEXT_EDITOR PAPAYA_USE_TINYMCE_GZIP Bedeutung Ob der Richtex-Editor verwendet werden soll Welcher Richtext-Editor verwendet werden soll (fckeditor oder tinymce) Ob TinyMCE komprimiert ausgeliefert werden soll (default = false) PAPAYA_USE_TINYMCE_VERSION Welche TinyMCE Version verwendet werden soll (2 oder 3) PAPAYA_WEBSITE_REVISION Papaya Revision, entspricht PAPA- YA_WEBSITE_REVISION, wird in /revision.inc.php beim Export gesetzt. PAPAYA_VERSION Die papaya Version, entspricht PAPA- YA_VERSION_STRING, im Normalfall 5 Die folgenden Parameter sind nur für die Frontend-Ausgabe von Interesse, hier stehen sie nur der Vollständigkeit halber und sollten ggf. in Themes/Templates übernommen werden, falls nicht schon vorhanden. Parameter PAGE_MODE_PUBLIC PAGE_OUTPUTMODE_CURRENT PAGE_OUTPUTMODE_DEFAULT Tabelle 6.2: Parameter im papaya Backend Template Bedeutung FRONTEND: Ob die Seite öffentlich ist oder nicht. FRONTEND: Der aktuelle Ausgabemodus der Seite (html, pdf,...) FRONTEND: Der Standardausgabemodus der Seite PAGE_THEME FRONTEND: Welches Theme verwendet wird, entspricht der papaya Konstante PAPA- YA_LAYOUT_THEME PAGE_THEME_PATH PAGE_THEME_PATH_LOCAL FRONTEND: relativer Pfad zum aktuellen Theme, z.b. /my-cms/papaya-themes/my-theme/ oder CDN (Content Delivery Network) Theme-URL FRONTEND: relativer Pfad zum aktuellen Theme, z.b. /papaya-themes/default-theme/ 161

166 6 Backend-Komponenten Abbildung 6.1: PAGE_ICON und PAGE_TITLE Elemente Im Default Skins-Ordner ist die style.xsl das Haupttemplate. Dort wird die grundlegende Struktur der Seite festgelegt und weitere Sub-Templates eingebunden. Im Unterordner controls liegen unterteilt die einzelnen Elemente, die verwendet werden können. Im Unterordner lang liegen Sprachdefinitionen, für die wenigen Stellen, an denen die Ausgabe nicht über das Phrasenmodul übersetzt werden können oder sollen. calendar.xsl Dieses Template erstellt eine Monatsübersicht für einen Kalender. dialogs.xsl Dieses Template erstellt ein Formular, das z.b. mit base_dialog generiert wurde. 162

167 6.1 Übersicht über die verfügbaren Komponenten Abbildung 6.2: Beispiel für ein Formular generics.xsl Dieses Template enthält die Ausgabe für Basis-HTML Elemente wie a, b, div, span, img, script, noscript, object, Flash-Objekt, checkbox, dann papaya-spezifisches wie glyph, iconurl sowie die Hilfs-Templates float-fix, replace-string und escape-quotes-js, noescape node(). grid.xsl Dieses Template wird derzeit (1/2009) ausschließlich im Who-is-Who verwendet. iconpanel.xsl Dieses Template erstellt eine vertikale Liste von Icons. Benutzt wird dieses Template in der Online-Hilfe sowie im Nachrichtensystem von papaya CMS. 163

168 6 Backend-Komponenten Abbildung 6.3: Beispielausgabe für iconpanel listview.xsl Dieses Template erstellt eine tabellarische Liste. Diese sehr flexible Komponente wird zusammen mit Dialog wohl am häufigsten verwendet. Im Modus tile wird dieses Template auch für die Ausgabe der Iconübersicht verwendet. Abbildung 6.4: einfache Listview Abbildung 6.5: aufklappbare Listview mit Nodes 164

169 6.1 Übersicht über die verfügbaren Komponenten Abbildung 6.6: komplexe Listview mit Paging, Spaltenüberschriften, Sortierung, Formular und Footer Abbildung 6.7: Listview im tiled Modus login.xsl Dieses Template wird ausschließlich für das Loginformular für das Backend verwendet. 165

170 6 Backend-Komponenten Abbildung 6.8: Das Loginformular menus.xsl Dieses Template generiert eine Menü- oder Werkzeugleiste mit Icon/Text-Buttons. Abbildung 6.9: Menü- oder Toolbar messages.xsl Dieses Template generiert Nachrichtenboxen und Bestätigungsdialoge. Abbildung 6.10: Nachrichtenbox mit einer Nachricht Abbildung 6.11: Nachrichtenbox mit mehreren Nachrichten 166

171 6.1 Übersicht über die verfügbaren Komponenten panel.xsl Dieses Template generiert Blöcke (Panels), die in den einzelnen Spalten des Layouts ausgegeben werden. Intern wird Panel für die meisten Ausgabeblöcke verwendet. sheet.xsl Dieses Template generiert einen größeren Informationsblock. Abbildung 6.12: Beispielausgabe für sheet Abbildung 6.13: Umfangreiches Beispiel für sheet Abbildung 6.14: Teletype-Beispiel für sheet 167

172 6 Backend-Komponenten thumbnails.xsl Dieses Template generiert eine Thumbnail-Liste. Das wird für den Datei-Browser verwendet. Abbildung 6.15: Beispielausgabe für Thumbnail-Liste 168

Einrichten des IIS für VDF WebApp. Einrichten des IIS (Internet Information Server) zur Verwendung von Visual DataFlex Web Applications

Einrichten des IIS für VDF WebApp. Einrichten des IIS (Internet Information Server) zur Verwendung von Visual DataFlex Web Applications Einrichten des IIS (Internet Information Server) zur Verwendung von Visual DataFlex Web Applications Windows 8 Systemsteuerung > Programme > Windows Features aktivieren / deaktivieren > Im Verzeichnisbaum

Mehr

Guide DynDNS und Portforwarding

Guide DynDNS und Portforwarding Guide DynDNS und Portforwarding Allgemein Um Geräte im lokalen Netzwerk von überall aus über das Internet erreichen zu können, kommt man um die Themen Dynamik DNS (kurz DynDNS) und Portweiterleitung(auch

Mehr

Adminer: Installationsanleitung

Adminer: Installationsanleitung Adminer: Installationsanleitung phpmyadmin ist bei uns mit dem Kundenmenüpasswort geschützt. Wer einer dritten Person Zugriff auf die Datenbankverwaltung, aber nicht auf das Kundenmenü geben möchte, kann

Mehr

Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten

Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten Version 1.0 Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten In unserer Anleitung zeigen wir Dir, wie Du Blogbeiträge

Mehr

Facebook I-Frame Tabs mit Papoo Plugin erstellen und verwalten

Facebook I-Frame Tabs mit Papoo Plugin erstellen und verwalten Facebook I-Frame Tabs mit Papoo Plugin erstellen und verwalten Seit Anfang Juni 2012 hat Facebook die Static FBML Reiter deaktiviert, so wird es relativ schwierig für Firmenseiten eigene Impressumsreiter

Mehr

Installation des edu- sharing Plug- Ins für Moodle

Installation des edu- sharing Plug- Ins für Moodle Installation des edu- sharing Plug- Ins für Moodle [edu-sharing Team] [Dieses Dokument beschreibt die Installation und Konfiguration des edu-sharing Plug-Ins für das LMS Moodle.] edu- sharing / metaventis

Mehr

Installation von Wordpress

Installation von Wordpress Installation von Wordpress Wordpress (http://wordpress-deutschland.org/) ist ein sehr bekanntes Blog-Script, welches Ihnen ermöglicht, schnell und einfach ein Blog auf Ihrem Webspace zu installieren. Sie

Mehr

Artikel Schnittstelle über CSV

Artikel Schnittstelle über CSV Artikel Schnittstelle über CSV Sie können Artikeldaten aus Ihrem EDV System in das NCFOX importieren, dies geschieht durch eine CSV Schnittstelle. Dies hat mehrere Vorteile: Zeitersparnis, die Karteikarte

Mehr

Installation des CMS-Systems Contao auf einem Windows-Rechner mit XAMPP

Installation des CMS-Systems Contao auf einem Windows-Rechner mit XAMPP XAMPP Installation des CMS-Systems Contao auf einem Windows-Rechner mit XAMPP XAMPP ist eine vollständig kostenlose, leicht zu installierende Apache-Distribution, die MySQL, PHP und Perl enthält. Das XAMPP

Mehr

INSTALLATION. Voraussetzungen

INSTALLATION. Voraussetzungen INSTALLATION Voraussetzungen Um Papoo zu installieren brauchen Sie natürlich eine aktuelle Papoo Version die Sie sich auf der Seite http://www.papoo.de herunterladen können. Papoo ist ein webbasiertes

Mehr

SANDBOXIE konfigurieren

SANDBOXIE konfigurieren SANDBOXIE konfigurieren für Webbrowser und E-Mail-Programme Dies ist eine kurze Anleitung für die grundlegenden folgender Programme: Webbrowser: Internet Explorer, Mozilla Firefox und Opera E-Mail-Programme:

Mehr

Avira Management Console 2.6.1 Optimierung für großes Netzwerk. Kurzanleitung

Avira Management Console 2.6.1 Optimierung für großes Netzwerk. Kurzanleitung Avira Management Console 2.6.1 Optimierung für großes Netzwerk Kurzanleitung Inhaltsverzeichnis 1. Einleitung... 3 2. Aktivieren des Pull-Modus für den AMC Agent... 3 3. Ereignisse des AMC Agent festlegen...

Mehr

Step by Step Webserver unter Windows Server 2003. von Christian Bartl

Step by Step Webserver unter Windows Server 2003. von Christian Bartl Step by Step Webserver unter Windows Server 2003 von Webserver unter Windows Server 2003 Um den WWW-Server-Dienst IIS (Internet Information Service) zu nutzen muss dieser zunächst installiert werden (wird

Mehr

HOWTO Update von MRG1 auf MRG2 bei gleichzeitigem Update auf Magento CE 1.4 / Magento EE 1.8

HOWTO Update von MRG1 auf MRG2 bei gleichzeitigem Update auf Magento CE 1.4 / Magento EE 1.8 Update von MRG1 auf MRG2 bei gleichzeitigem Update auf Magento CE 1.4 / Magento EE 1.8 Schritt 1: Altes Modul-Paket vollständig deinstallieren Die neuen MRG-Module sind aus dem Scope local in den Scope

Mehr

INSTALLATIONSANLEITUNG

INSTALLATIONSANLEITUNG INSTALLATIONSANLEITUNG MASTER UPDATE 2.1.0.4 2014 Gambio GmbH. www.gambio.de Inhaltsverzeichnis 1 Changelog 3 2 Datensicherung 3 3 Installation Master Update 4 3.1 Update von Shopsystemen v2.0.7c bis v2.0.15.4

Mehr

Contao (Teil 37): Suchmaschinenoptimierung (1)

Contao (Teil 37): Suchmaschinenoptimierung (1) Web >> Contao Contao (Teil 37): Suchmaschinenoptimierung (1) Autor: daniel_koch Inhalt: Webseiten können eigentlich nur erfolgreich sein, wenn sie auch vernünftig über Suchmaschinen gefunden werden. Grund

Mehr

Ablaufbeschreibung für das neu Aufsetzen von Firebird und Interbase Datenbanken mit der IBOConsole

Ablaufbeschreibung für das neu Aufsetzen von Firebird und Interbase Datenbanken mit der IBOConsole Lavid-F.I.S. Ablaufbeschreibung für das neu Aufsetzen von Firebird und Interbase Datenbanken mit der Lavid Software GmbH Dauner Straße 12, D-41236 Mönchengladbach http://www.lavid-software.net Support:

Mehr

Plugins. Stefan Salich (sallo@gmx.de) Stand 2008-11-21

Plugins. Stefan Salich (sallo@gmx.de) Stand 2008-11-21 Plugins Stefan Salich (sallo@gmx.de) Stand 2008-11-21 Inhaltsverzeichnis 0 Einleitung...3 0.1 Sinn und Zweck...3 0.2 Änderungsübersicht...3 0.3 Abkürzungsverzeichnis...3 1 Einfügen eines Plugins...4 1.1

Mehr

www.flatbooster.com FILEZILLA HANDBUCH

www.flatbooster.com FILEZILLA HANDBUCH www.flatbooster.com FILEZILLA HANDBUCH deutsche Auflage Datum: 12.03.2011 Version: 1.0.2 Download: http://flatbooster.com/support Inhaltsverzeichnis 1 Filezilla FTP Programm 1 1.1 Filezilla installieren.................................

Mehr

Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge

Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge Ab der Version forma 5.5 handelt es sich bei den Orientierungshilfen der Architekten-/Objektplanerverträge nicht

Mehr

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3 Handbuch Fischertechnik-Einzelteiltabelle V3.7.3 von Markus Mack Stand: Samstag, 17. April 2004 Inhaltsverzeichnis 1. Systemvorraussetzungen...3 2. Installation und Start...3 3. Anpassen der Tabelle...3

Mehr

Ihr CMS für die eigene Facebook Page - 1

Ihr CMS für die eigene Facebook Page - 1 Ihr CMS für die eigene Facebook Page Installation und Einrichten eines CMS für die Betreuung einer oder mehrer zusätzlichen Seiten auf Ihrer Facebook Page. Anpassen der "index.php" Installieren Sie das

Mehr

Tutorial - www.root13.de

Tutorial - www.root13.de Tutorial - www.root13.de Netzwerk unter Linux einrichten (SuSE 7.0 oder höher) Inhaltsverzeichnis: - Netzwerk einrichten - Apache einrichten - einfaches FTP einrichten - GRUB einrichten Seite 1 Netzwerk

Mehr

Einrichtung Secure-FTP

Einrichtung Secure-FTP Einrichtung Secure-FTP ONEGroup Hochriesstrasse 16 83101 Rohrdorf Steffen Prochnow Hochriesstrasse 16 83101 Rohrdorf Tel.: (08032) 989 492 Fax.: (01212) 568 596 498 agb@onegroup.de 1. Vorwort... 2 2. Einrichtung

Mehr

Installationsbeschreibung Import / ATLAS / PV Zollsystem für die EDV-Abteilung

Installationsbeschreibung Import / ATLAS / PV Zollsystem für die EDV-Abteilung Seite 1/11 Installationsbeschreibung Import / ATLAS / PV Zollsystem für die EDV-Abteilung 1. WICHTIGE HINWEISE Anbei erhalten Sie das Import /PV ATLAS NCTS Update Version V8.4.1 Build: 404, welches Sie

Mehr

Folgende Einstellungen sind notwendig, damit die Kommunikation zwischen Server und Client funktioniert:

Folgende Einstellungen sind notwendig, damit die Kommunikation zwischen Server und Client funktioniert: Firewall für Lexware professional konfigurieren Inhaltsverzeichnis: 1. Allgemein... 1 2. Einstellungen... 1 3. Windows XP SP2 und Windows 2003 Server SP1 Firewall...1 4. Bitdefender 9... 5 5. Norton Personal

Mehr

AnNoText. AnNoText Online-Update. Copyright Wolters Kluwer Deutschland GmbH

AnNoText. AnNoText Online-Update. Copyright Wolters Kluwer Deutschland GmbH Copyright Wolters Kluwer Deutschland GmbH AnNoText AnNoText Online-Update Wolters Kluwer Deutschland GmbH Software + Services Legal Robert-Bosch-Straße 6 D-50354 Hürth Telefon (02 21) 9 43 73-6000 Telefax

Mehr

etermin Einbindung in Outlook

etermin Einbindung in Outlook etermin Einbindung in Outlook 1. Einführung Über etermin gebuchte Termine können bei Bedarf auch mit externen Terminkalendern, wie zum Beispiel Outlook, ical oder Google synchronisiert werden. Dieses Dokument

Mehr

Live Update (Auto Update)

Live Update (Auto Update) Live Update (Auto Update) Mit der Version 44.20.00 wurde moveit@iss+ um die Funktion des Live Updates (in anderen Programmen auch als Auto Update bekannt) für Programm Updates erweitert. Damit Sie auch

Mehr

Die Dateiablage Der Weg zur Dateiablage

Die Dateiablage Der Weg zur Dateiablage Die Dateiablage In Ihrem Privatbereich haben Sie die Möglichkeit, Dateien verschiedener Formate abzulegen, zu sortieren, zu archivieren und in andere Dateiablagen der Plattform zu kopieren. In den Gruppen

Mehr

Lokale Installation von DotNetNuke 4 ohne IIS

Lokale Installation von DotNetNuke 4 ohne IIS Lokale Installation von DotNetNuke 4 ohne IIS ITM GmbH Wankelstr. 14 70563 Stuttgart http://www.itm-consulting.de Benjamin Hermann hermann@itm-consulting.de 12.12.2006 Agenda Benötigte Komponenten Installation

Mehr

Themen. Apache Webserver Konfiguration. Verzeichnisse für Web-Applikationen. Server Side Includes

Themen. Apache Webserver Konfiguration. Verzeichnisse für Web-Applikationen. Server Side Includes Themen Apache Webserver Konfiguration Verzeichnisse für Web-Applikationen Server Side Includes Apache Webserver Konfiguration des Apache Webservers Server-Einstellungen in der httpd.conf-datei Einteilung

Mehr

-Bundle auf Ihrem virtuellen Server installieren.

-Bundle auf Ihrem virtuellen Server installieren. Anleitung: Confixx auf virtuellem Server installieren Diese Anleitung beschreibt Ihnen, wie Sie das Debian-Confixx- -Bundle auf Ihrem virtuellen Server installieren. 1. Schritt: Rufen Sie die Adresse http://vsadmin.host-4-you.de

Mehr

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten In dem Virtuellen Seminarordner werden für die Teilnehmerinnen und Teilnehmer des Seminars alle für das Seminar wichtigen Informationen,

Mehr

Erstellung botoptimierter Partnerlinks

Erstellung botoptimierter Partnerlinks Erstellung botoptimierter Partnerlinks Um bestimmte Aktionen und deren Rückläufer übersichtlich tracken zu können, bietet das RedSYS Partnerprogramm in Verbindung mit den botoptimierten RedSYS-Links, die

Mehr

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Objektorientierte Programmierung für Anfänger am Beispiel PHP Objektorientierte Programmierung für Anfänger am Beispiel PHP Johannes Mittendorfer http://jmittendorfer.hostingsociety.com 19. August 2012 Abstract Dieses Dokument soll die Vorteile der objektorientierten

Mehr

Administrator Handbuch

Administrator Handbuch SPTools Extension Keys: sptools_fal_base sptools_fal_driver SPTools Version: 1 Extension Version: 1.0.2 Inhaltsverzeichnis... 1 1. Einleitung... 2 2. Systemanforderungen... 3 3. SPTools FAL Installation...

Mehr

Anleitung zum Login. über die Mediteam- Homepage und zur Pflege von Praxisnachrichten

Anleitung zum Login. über die Mediteam- Homepage und zur Pflege von Praxisnachrichten Anleitung zum Login über die Mediteam- Homepage und zur Pflege von Praxisnachrichten Stand: 18.Dezember 2013 1. Was ist der Mediteam-Login? Alle Mediteam-Mitglieder können kostenfrei einen Login beantragen.

Mehr

Datensicherung. Beschreibung der Datensicherung

Datensicherung. Beschreibung der Datensicherung Datensicherung Mit dem Datensicherungsprogramm können Sie Ihre persönlichen Daten problemlos Sichern. Es ist möglich eine komplette Datensicherung durchzuführen, aber auch nur die neuen und geänderten

Mehr

Bedienungsanleitung. Stand: 26.05.2011. Copyright 2011 by GEVITAS GmbH www.gevitas.de

Bedienungsanleitung. Stand: 26.05.2011. Copyright 2011 by GEVITAS GmbH www.gevitas.de GEVITAS-Sync Bedienungsanleitung Stand: 26.05.2011 Copyright 2011 by GEVITAS GmbH www.gevitas.de Inhalt 1. Einleitung... 3 1.1. Installation... 3 1.2. Zugriffsrechte... 3 1.3. Starten... 4 1.4. Die Menü-Leiste...

Mehr

1. Zuerst muss der Artikel angelegt werden, damit später die Produktvarianten hinzugefügt werden können.

1. Zuerst muss der Artikel angelegt werden, damit später die Produktvarianten hinzugefügt werden können. Produktvarianten und Downloads erstellen Produktvarianten eignen sich um Artikel mit verschiedenen Optionen wie bspw. ein Herrenhemd in den Farben blau, grün und rot sowie in den Größen S, M und L zu verkaufen.

Mehr

Um ein solches Dokument zu erzeugen, muss eine Serienbriefvorlage in Word erstellt werden, das auf die von BüroWARE erstellte Datei zugreift.

Um ein solches Dokument zu erzeugen, muss eine Serienbriefvorlage in Word erstellt werden, das auf die von BüroWARE erstellte Datei zugreift. Briefe Schreiben - Arbeiten mit Word-Steuerformaten Ab der Version 5.1 stellt die BüroWARE über die Word-Steuerformate eine einfache Methode dar, Briefe sowie Serienbriefe mit Hilfe der Korrespondenzverwaltung

Mehr

Betriebshandbuch. MyInTouch Import Tool

Betriebshandbuch. MyInTouch Import Tool Betriebshandbuch MyInTouch Import Tool Version 2.0.5, 17.08.2004 2 MyInTouch Installationshandbuch Inhaltsverzeichnis Inhaltsverzeichnis... 2 Bevor Sie beginnen... 3 Einleitung...3 Benötigte Daten...3

Mehr

BEDIENUNG ABADISCOVER

BEDIENUNG ABADISCOVER BEDIENUNG ABADISCOVER Juni 2005 / EMO v.2005.1 Diese Unterlagen sind urheberrechtlich geschützt. Alle Rechte, auch die der Übersetzung, des Nachdrucks und der Vervielfältigung der Unterlagen, oder Teilen

Mehr

Einfache und effiziente Zusammenarbeit in der Cloud. EASY-PM Office Add-Ins Handbuch

Einfache und effiziente Zusammenarbeit in der Cloud. EASY-PM Office Add-Ins Handbuch Einfache und effiziente Zusammenarbeit in der Cloud EASY-PM Office Add-Ins Handbuch Inhaltsverzeichnis 1. Einführung... 3 2. Ribbonmenü... 4 3. Dokument... 5 3.1 Öffnen... 5 3.2 Speichern... 6 3.3 Speichern

Mehr

Icinga Teil 2. Andreas Teuchert. 25. Juli 2014

Icinga Teil 2. Andreas Teuchert. 25. Juli 2014 Icinga Teil 2 Andreas Teuchert 25. Juli 2014 1 Nagios-Plugins Programme, die den Status von Diensten überprüfen können liegen in /usr/lib/nagios/plugins/ werden von Icinga aufgerufen, geben Status über

Mehr

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1

CMS.R. Bedienungsanleitung. Modul Cron. Copyright 10.09.2009. www.sruttloff.de CMS.R. - 1 - Revision 1 CMS.R. Bedienungsanleitung Modul Cron Revision 1 Copyright 10.09.2009 www.sruttloff.de CMS.R. - 1 - WOZU CRON...3 VERWENDUNG...3 EINSTELLUNGEN...5 TASK ERSTELLEN / BEARBEITEN...6 RECHTE...7 EREIGNISSE...7

Mehr

Powermanager Server- Client- Installation

Powermanager Server- Client- Installation Client A Server Client B Die Server- Client- Funktion ermöglicht es ein zentrales Powermanager Projekt von verschiedenen Client Rechnern aus zu bedienen. 1.0 Benötigte Voraussetzungen 1.1 Sowohl am Server

Mehr

FTP-Server einrichten mit automatischem Datenupload für SolarView@Fritzbox

FTP-Server einrichten mit automatischem Datenupload für SolarView@Fritzbox FTP-Server einrichten mit automatischem Datenupload für SolarView@Fritzbox Bitte beachten: Der im folgenden beschriebene Provider "www.cwcity.de" dient lediglich als Beispiel. Cwcity.de blendet recht häufig

Mehr

Update und Konfiguraton mit dem ANTLOG Konfigurations-Assistenten

Update und Konfiguraton mit dem ANTLOG Konfigurations-Assistenten Update und Konfiguraton mit dem ANTLOG Konfigurations-Assistenten Der Konfigurations-Assistent wurde entwickelt, um die unterschiedlichen ANTLOG-Anwendungen auf den verschiedensten Umgebungen automatisiert

Mehr

Patch Management mit

Patch Management mit Patch Management mit Installation von Hotfixes & Patches Inhaltsverzeichnis dieses Dokuments Einleitung...3 Wie man einen Patch installiert...4 Patch Installation unter UliCMS 7.x.x bis 8.x.x...4 Patch

Mehr

ShopwareAutoinvoice Installations- und Benutzeranleitung

ShopwareAutoinvoice Installations- und Benutzeranleitung ShopwareAutoinvoice Installations- und Benutzeranleitung 1. Installation Wechseln Sie in das Shop Backend unter /backend. Loggen Sie sich ein und wählen Sie Einstellungen -> Plugin Manager. Klicken Sie

Mehr

Leitfaden zur ersten Nutzung der R FOM Portable-Version für Windows (Version 1.0)

Leitfaden zur ersten Nutzung der R FOM Portable-Version für Windows (Version 1.0) Leitfaden zur ersten Nutzung der R FOM Portable-Version für Windows (Version 1.0) Peter Koos 03. Dezember 2015 0 Inhaltsverzeichnis 1 Voraussetzung... 3 2 Hintergrundinformationen... 3 2.1 Installationsarten...

Mehr

Anleitung: Confixx auf virtuellem Server installieren

Anleitung: Confixx auf virtuellem Server installieren Anleitung: Confixx auf virtuellem Server installieren Diese Anleitung beschreibt Ihnen, wie Sie Confixx 3.0 auf Ihrem virtuellen Server installieren. 1. Schritt: Rufen Sie die Adresse www.vpsadmin.de in

Mehr

Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht:

Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht: Beiträge erstellen in Joomla Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht: Abbildung 1 - Kontrollzentrum Von hier aus kann man zu verschiedene Einstellungen

Mehr

Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite.

Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite. ewon - Technical Note Nr. 003 Version 1.2 Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite. Übersicht 1. Thema 2. Benötigte Komponenten 3. Downloaden der Seiten und aufspielen auf

Mehr

Musterlösung für Schulen in Baden-Württemberg. Windows 2003. Basiskurs Windows-Musterlösung. Version 3. Stand: 19.12.06

Musterlösung für Schulen in Baden-Württemberg. Windows 2003. Basiskurs Windows-Musterlösung. Version 3. Stand: 19.12.06 Musterlösung für Schulen in Baden-Württemberg Windows 2003 Basiskurs Windows-Musterlösung Version 3 Stand: 19.12.06 Impressum Herausgeber Zentrale Planungsgruppe Netze (ZPN) am Kultusministerium Baden-Württemberg

Mehr

Einrichten einer mehrsprachigen Webseite mit Joomla (3.3.6)

Einrichten einer mehrsprachigen Webseite mit Joomla (3.3.6) Einrichten einer mehrsprachigen Webseite mit Joomla (3.3.6) 1. Loggen Sie sich im Administratorbereich ein und gehen Sie auf Extension > Extension Manager 2. Wählen Sie Install languages 3. Klicken Sie

Mehr

Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH

Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH Amt für Informatik Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH Anleitung vom 12. September 2009 Version: 1.0 Ersteller: Ressort Sicherheit Zielgruppe: Benutzer von SSLVPN.TG.CH Kurzbeschreib:

Mehr

OP-LOG www.op-log.de

OP-LOG www.op-log.de Verwendung von Microsoft SQL Server, Seite 1/18 OP-LOG www.op-log.de Anleitung: Verwendung von Microsoft SQL Server 2005 Stand Mai 2010 1 Ich-lese-keine-Anleitungen 'Verwendung von Microsoft SQL Server

Mehr

.htaccess HOWTO. zum Schutz von Dateien und Verzeichnissen mittels Passwortabfrage

.htaccess HOWTO. zum Schutz von Dateien und Verzeichnissen mittels Passwortabfrage .htaccess HOWTO zum Schutz von Dateien und Verzeichnissen mittels Passwortabfrage Stand: 21.06.2015 Inhaltsverzeichnis 1. Vorwort...3 2. Verwendung...4 2.1 Allgemeines...4 2.1 Das Aussehen der.htaccess

Mehr

Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken.

Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken. Seite erstellen Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken. Es öffnet sich die Eingabe Seite um eine neue Seite zu erstellen. Seiten Titel festlegen Den neuen

Mehr

Wie richten Sie Ihr Web Paket bei Netpage24 ein

Wie richten Sie Ihr Web Paket bei Netpage24 ein Wie richten Sie Ihr Web Paket bei Netpage24 ein Eine kostenlose ebook Anleitung von Netpage24 - Webseite Information 1 E-Mail Bestätigung... 3 2 Ticketsystem... 3 3 FTP Konto anlegen... 4 4 Datenbank anlegen...

Mehr

Aufklappelemente anlegen

Aufklappelemente anlegen Aufklappelemente anlegen Dieses Dokument beschreibt die grundsätzliche Erstellung der Aufklappelemente in der mittleren und rechten Spalte. Login Melden Sie sich an der jeweiligen Website an, in dem Sie

Mehr

TeamSpeak3 Einrichten

TeamSpeak3 Einrichten TeamSpeak3 Einrichten Version 1.0.3 24. April 2012 StreamPlus UG Es ist untersagt dieses Dokument ohne eine schriftliche Genehmigung der StreamPlus UG vollständig oder auszugsweise zu reproduzieren, vervielfältigen

Mehr

Seminar DWMX 2004. DW Session 015

Seminar DWMX 2004. DW Session 015 Seminar DWMX 2004 DW Session 015 Veröffentlichen der lokalen Website Bis jetzt sind die Daten immer lokal in Dreamweaver bearbeitet und über die interne Vorschau mit F12/Strg.+F12 im Browser betrachtet

Mehr

DHL Online Retoure - Magento Extension zur Erstellung der Retouren-Labels durch den Kunden im Frontend

DHL Online Retoure - Magento Extension zur Erstellung der Retouren-Labels durch den Kunden im Frontend DHL Online Retoure - Magento Extension zur Erstellung der Retouren-Labels durch den Kunden im Frontend Stand: 19/08/2014 1/11 DHL Online Retoure - Endbenutzer-Dokumentation 1 Voraussetzungen 3 1.1 Magento

Mehr

Warenwirtschaft Handbuch - Administration. 2013 www.addware.de

Warenwirtschaft Handbuch - Administration. 2013 www.addware.de Warenwirtschaft Handbuch - Administration 2 Warenwirtschaft Inhaltsverzeichnis Vorwort 0 Teil I Administration 3 1 Datei... 4 2 Datenbank... 6 3 Warenwirtschaft... 12 Erste Schritte... 13 Benutzerverwaltung...

Mehr

Visualisierung auf Büro PC s mit dem ibricks Widget

Visualisierung auf Büro PC s mit dem ibricks Widget Automation Server Visualisierung auf Büro PC s mit dem Widget Solutions Industriestrasse 25A CH-3178 Bösingen mail@.ch www..ch Tel +41 31 5 110 110 Fax+41 31 5 110 112 Solutions Bausteine zum intelligenten

Mehr

Die MSDE ist nicht mehr Bestandteil des Installationspaketes der GETECO contura

Die MSDE ist nicht mehr Bestandteil des Installationspaketes der GETECO contura Hinweis zur MSDE: Die MSDE ist nicht mehr Bestandteil des Installationspaketes der GETECO contura Vor Beginn der Installationsarbeiten ist daher die MSDE 2000A von der Microsoft Download-Seite herunter

Mehr

DOKUMENTATION VOGELZUCHT 2015 PLUS

DOKUMENTATION VOGELZUCHT 2015 PLUS DOKUMENTATION VOGELZUCHT 2015 PLUS Vogelzucht2015 App für Geräte mit Android Betriebssystemen Läuft nur in Zusammenhang mit einer Vollversion vogelzucht2015 auf einem PC. Zusammenfassung: a. Mit der APP

Mehr

WordPress. Dokumentation

WordPress. Dokumentation WordPress Dokumentation Backend-Login In das Backend gelangt man, indem man hinter seiner Website-URL einfach ein /wp-admin dranhängt www.domain.tld/wp-admin Dabei gelangt man auf die Administrationsoberfläche,

Mehr

Das Einzelplatz-Versionsupdate unter Version Bp810

Das Einzelplatz-Versionsupdate unter Version Bp810 Das Einzelplatz-Versionsupdate unter Version Bp810 Grundsätzliches für alle Installationsarten ACHTUNG: Prüfen Sie vor der Installation die aktuellen Systemanforderungen für die neue BANKETTprofi Version.

Mehr

INTERNETZUGANG WLAN-ROUTER ANLEITUNG FIRMWARE-UPDATE SIEMENS

INTERNETZUGANG WLAN-ROUTER ANLEITUNG FIRMWARE-UPDATE SIEMENS Wichtige Hinweise: Das Firmware-Update geschieht auf eigene Gefahr! NetCologne übernimmt keine Verantwortung für mögliche Schäden an Ihrem WLAN-Router, die in Zusammenhang mit dem Firmware-Update oder

Mehr

Medea3 Print-Client (m3_print)

Medea3 Print-Client (m3_print) Medea3 Print-Client (m3_print) Installationsanleitung Installationsanleitung m3_print.exe...2 1. Installieren von Ghostskript und Ghostview...2 1. Ghostskript...2 2. Ghostview...3 2. Kopieren des Print-Client-Programms...6

Mehr

Snippets - das Erstellen von "Code- Fragmenten" - 1

Snippets - das Erstellen von Code- Fragmenten - 1 Snippets - das Erstellen von "Code- Fragmenten" Das Erstellen von "Code- Fragmenten", welche mit dem TinyMCE ausgewählt werden können. Grundlegendes: Die Datei, welche die in Folge erklärten Daten und

Mehr

Anleitung BFV-Widget-Generator

Anleitung BFV-Widget-Generator Anleitung BFV-Widget-Generator Seite 1 von 6 Seit dem 1. Oktober 2014 hat der Bayerische Fußball-Verband e.v. neue Widgets und einen neuen Baukasten zur Erstellung dieser Widgets veröffentlicht. Im Folgenden

Mehr

Stundenerfassung Version 1.8 Anleitung Arbeiten mit Replikaten

Stundenerfassung Version 1.8 Anleitung Arbeiten mit Replikaten Stundenerfassung Version 1.8 Anleitung Arbeiten mit Replikaten 2008 netcadservice GmbH netcadservice GmbH Augustinerstraße 3 D-83395 Freilassing Dieses Programm ist urheberrechtlich geschützt. Eine Weitergabe

Mehr

Durchführung der Datenübernahme nach Reisekosten 2011

Durchführung der Datenübernahme nach Reisekosten 2011 Durchführung der Datenübernahme nach Reisekosten 2011 1. Starten Sie QuickSteuer Deluxe 2010. Rufen Sie anschließend über den Menüpunkt /Extras/Reisekosten Rechner den QuickSteuer Deluxe 2010 Reisekosten-Rechner,

Mehr

TimeMachine. Time CGI. Version 1.5. Stand 04.12.2013. Dokument: time.odt. Berger EDV Service Tulbeckstr. 33 80339 München

TimeMachine. Time CGI. Version 1.5. Stand 04.12.2013. Dokument: time.odt. Berger EDV Service Tulbeckstr. 33 80339 München Time CGI Version 1.5 Stand 04.12.2013 TimeMachine Dokument: time.odt Berger EDV Service Tulbeckstr. 33 80339 München Fon +49 89 13945642 Mail rb@bergertime.de Versionsangaben Autor Version Datum Kommentar

Mehr

GEORG.NET Anbindung an Ihr ACTIVE-DIRECTORY

GEORG.NET Anbindung an Ihr ACTIVE-DIRECTORY GEORG.NET Anbindung an Ihr ACTIVE-DIRECTORY Vorteile der Verwendung eines ACTIVE-DIRECTORY Automatische GEORG Anmeldung über bereits erfolgte Anmeldung am Betriebssystem o Sie können sich jederzeit als

Mehr

Einkaufslisten verwalten. Tipps & Tricks

Einkaufslisten verwalten. Tipps & Tricks Tipps & Tricks INHALT SEITE 1.1 Grundlegende Informationen 3 1.2 Einkaufslisten erstellen 4 1.3 Artikel zu einer bestehenden Einkaufsliste hinzufügen 9 1.4 Mit einer Einkaufslisten einkaufen 12 1.4.1 Alle

Mehr

HTBVIEWER INBETRIEBNAHME

HTBVIEWER INBETRIEBNAHME HTBVIEWER INBETRIEBNAHME Vorbereitungen und Systemvoraussetzungen... 1 Systemvoraussetzungen... 1 Betriebssystem... 1 Vorbereitungen... 1 Installation und Inbetriebnahme... 1 Installation... 1 Assistenten

Mehr

GS-Programme 2015 Allgemeines Zentralupdate

GS-Programme 2015 Allgemeines Zentralupdate GS-Programme 2015 Allgemeines Zentralupdate Impressum Business Software GmbH Primoschgasse 3 9020 Klagenfurt Copyright 2014 Business Software GmbH Die Inhalte und Themen in dieser Unterlage wurden mit

Mehr

Stammdatenanlage über den Einrichtungsassistenten

Stammdatenanlage über den Einrichtungsassistenten Stammdatenanlage über den Einrichtungsassistenten Schritt für Schritt zur fertig eingerichteten Hotelverwaltung mit dem Einrichtungsassistenten Bitte bereiten Sie sich, bevor Sie starten, mit der Checkliste

Mehr

ABB i-bus KNX. Software-Information. Melde- und Bedientableau. Typ: MT 701.2

ABB i-bus KNX. Software-Information. Melde- und Bedientableau. Typ: MT 701.2 Produkt: Melde- und Bedientableau Typ: MT 701.2 Aktuelles Anwendungsprogramm Plug-In für ETS 2 MT_701_2_ETS2_SOW_xx_V1-12a_de_en.exe Plug-In für ETS 3 MT_701_2_ETS3_SOW_xx_V1-12a_de_en.exe EIBTAB: MT_701_2_EIBTAB_SOW_de_V2-08-00A_EibTab+Firmware.EXE

Mehr

Einfügen von Bildern innerhalb eines Beitrages

Einfügen von Bildern innerhalb eines Beitrages Version 1.2 Einfügen von Bildern innerhalb eines Beitrages Um eigene Bilder ins Forum einzufügen, gibt es zwei Möglichkeiten. 1.) Ein Bild vom eigenem PC wird auf den Webspace von Baue-die-Bismarck.de

Mehr

HANDBUCH PHOENIX II - DOKUMENTENVERWALTUNG

HANDBUCH PHOENIX II - DOKUMENTENVERWALTUNG it4sport GmbH HANDBUCH PHOENIX II - DOKUMENTENVERWALTUNG Stand 10.07.2014 Version 2.0 1. INHALTSVERZEICHNIS 2. Abbildungsverzeichnis... 3 3. Dokumentenumfang... 4 4. Dokumente anzeigen... 5 4.1 Dokumente

Mehr

mehr funktionen, mehr e-commerce:

mehr funktionen, mehr e-commerce: mehr funktionen, mehr e-commerce: xt:commerce plugin Search Tag Cloud xt:commerce Plugin search tag cloud Wonach suchen Ihre Kunden? Nicht nur für andere Nutzer ist es interessant, welche Artikel Ihre

Mehr

Anleitung für TYPO3... 1. Bevor Sie beginnen... 2. Newsletter anlegen... 2. Inhalt platzieren und bearbeiten... 3. Neuen Inhalt anlegen...

Anleitung für TYPO3... 1. Bevor Sie beginnen... 2. Newsletter anlegen... 2. Inhalt platzieren und bearbeiten... 3. Neuen Inhalt anlegen... Seite 1 von 11 Anleitung für TYPO3 Inhalt Anleitung für TYPO3... 1 Bevor Sie beginnen... 2 Newsletter anlegen... 2 Inhalt platzieren und bearbeiten... 3 Neuen Inhalt anlegen... 3 Bestehenden Inhalt bearbeiten...

Mehr

my.green.ch... 2 Domänenübersicht... 4

my.green.ch... 2 Domänenübersicht... 4 my.green.ch... 2 Domänenadministrator... 2 Kundenadministrator... 3 Standard Benutzer... 3 Domänenübersicht... 4 Domänen... 5 Benutzer und E-Mail... 5 Liste der Benutzer... 5 Hosted Exchange... 7 Mail

Mehr

Meldung Lokale Anwendung inkompatibel oder Microsoft Silverlight ist nicht aktuell bei Anmeldung an lokal gespeicherter RWE SmartHome Anwendung

Meldung Lokale Anwendung inkompatibel oder Microsoft Silverlight ist nicht aktuell bei Anmeldung an lokal gespeicherter RWE SmartHome Anwendung Meldung Lokale Anwendung inkompatibel oder Microsoft Silverlight ist nicht aktuell bei Anmeldung an lokal gespeicherter RWE SmartHome Anwendung Nach dem Update auf die Version 1.70 bekommen Sie eine Fehlermeldung,

Mehr

lññáåé=iáåé===pìééçêíáåñçêã~íáçå=

lññáåé=iáåé===pìééçêíáåñçêã~íáçå= lññáåé=iáåé===pìééçêíáåñçêã~íáçå= Wie kann das LiveUpdate durchgeführt werden? Um das LiveUpdate durchzuführen, müssen alle Anwender die Office Line verlassen. Nur so ist gewährleistet, dass die Office

Mehr

BüroWARE Exchange Synchronisation Grundlagen und Voraussetzungen

BüroWARE Exchange Synchronisation Grundlagen und Voraussetzungen BüroWARE Exchange Synchronisation Grundlagen und Voraussetzungen Stand: 13.12.2010 Die BüroWARE SoftENGINE ist ab Version 5.42.000-060 in der Lage mit einem Microsoft Exchange Server ab Version 2007 SP1

Mehr

Information zum SQL Server: Installieren und deinstallieren. (Stand: September 2012)

Information zum SQL Server: Installieren und deinstallieren. (Stand: September 2012) Information zum SQL Server: Installieren und deinstallieren (Stand: September 2012) Um pulsmagic nutzen zu können, wird eine SQL-Server-Datenbank benötigt. Im Rahmen der Installation von pulsmagic wird

Mehr

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt Inhaltsverzeichnis Aufgabe... 1 Allgemein... 1 Active Directory... 1 Konfiguration... 2 Benutzer erstellen... 3 Eigenes Verzeichnis erstellen... 3 Benutzerkonto erstellen... 3 Profil einrichten... 5 Berechtigungen

Mehr

Kommunikations-Management

Kommunikations-Management Tutorial: Wie importiere und exportiere ich Daten zwischen myfactory und Outlook? Im vorliegenden Tutorial lernen Sie, wie Sie in myfactory Daten aus Outlook importieren Daten aus myfactory nach Outlook

Mehr

Collax E-Mail-Archivierung

Collax E-Mail-Archivierung Collax E-Mail-Archivierung Howto Diese Howto beschreibt wie die E-Mail-Archivierung auf einem Collax Server installiert und auf die Daten im Archiv zugegriffen wird. Voraussetzungen Collax Business Server

Mehr

Auto-Provisionierung tiptel 30x0 mit Yeastar MyPBX

Auto-Provisionierung tiptel 30x0 mit Yeastar MyPBX Allgemeines Auto-Provisionierung tiptel 30x0 mit Yeastar MyPBX Stand 21.11.2014 Die Yeastar MyPBX Telefonanlagen unterstützen die automatische Konfiguration der tiptel 3010, tiptel 3020 und tiptel 3030

Mehr