ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/papp.sdf
Revision: 1.2
Committed: Sun Feb 4 02:01:08 2001 UTC (25 years, 8 months ago) by root
Branch: MAIN
Changes since 1.1: +413 -405 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 !init OPT_STYLE="paper"
2    
3     !define DOC_NAME "PApp - Perl-Anwendungen für die Zukunft des WWW"
4     !define DOC_AUTHOR "Marc Lehmann <pcg@goof.com>"
5     !build_title
6    
7 root 1.2 H1: PApp - Wie beschreibt man ein Chamäleon?
8 root 1.1
9     PApp ist schwer zu beschreiben, da es sich nicht auf ein spezielles
10     Problem spezialisiert sondern möglichst eine offene Universallösung sein
11     will. Unter anderem ist PApp:
12    
13     - ein Embedded-Perl-Dialekt. Es gibt verschiedene Formen: Ein "literal
14     programming style", der nicht XML-konform ist sondern beliebige Daten
15     ausgeben kann und viele Möglichkeiten des Einbettens von Perl in
16     XML. Schliesslich gibt es noch den Standard-XML-Dialekt, der eine Mischung
17     aus beidem darstellt.
18    
19     - Perl-Module, die das Arbeiten in einer CGI-artigen Umgebung
20     erlauben. Die Umgebung hält sich mehr an Apache, ist jedoch unabhängig
21     davon, ob die PApp-Anwendung in einer CGI-Umgebung, unter mod_perl oder
22     unter CGI::SpeedyCGI ausgeführt wird.
23    
24     - Eine Bibliothek (aus vielen Modulen), die das Arbeiten mit HTML, XML,
25     SQL und anderen, häufig benutzten Umständlichkeiten vereinfacht.
26    
27     - Eine grosse "State-Maschine", die technisch getrennte Programmteile
28     (z.B. CGI) logisch zu {{einer}} Applikation zusammenfasst.
29    
30     - Ein XSLT-Stylesheet-Prozessor. Damit kann man Layout und Inhalt
31     voneinander trennen. Oder auch Ausgabeformat (PDF/HTML/XML etc.) vom
32     Layout. Oder vom Inhalt...
33    
34     H2: Warum PApp geschrieben wurde
35    
36     Grosse und kleine Applikationen für das WWW zu erstellen ist sehr
37     arbeitsaufwendig. Session-Variablen kennt Perl nicht, Session- und
38     Usertracking natürlich auch nicht. Es gibt sehr gute Module, die einem
39     einen Teil der Arbeit abnehmen, aber es ist immer sehr aufwendig und
40     umständlich. Dies führt zu unübersichtlichen Programmen, die noch dazu
41     auf viele Dateien aufgeteilt sind, die nicht unbedingt der inneren Logik
42     des Programmes entsprechen. Auch Sicherheitsfehler (wie das Übergeben
43     von sicherheitsrelevanten Daten über {{hidden-fields}} moder ähnliches)
44     passieren schnell, schliesslich muss man sich bei jeder Seite überlegen,
45     wie man seine Daten weiterreicht.
46    
47     Datenbankabfragen, das Einbauen des Layouts sind sehr
48     umständlich. Internationalisierung existiert praktisch nicht.
49    
50     PApp vereinfacht alle diese Probleme, indem es sie weitestgehend
51     automatisiert.
52    
53     H1: Grundlegende PApp-Features oder "Nie wieder CGI"
54    
55 root 1.2 Zunächst möchte ich einige der vielen Features von PApp vorstellen
56     (natürlich die wichtigsten ;). Wem das zu langweilig ist und erstmal
57     eine richtige PApp-Applikation sehen will, sollte zum nächsten Abschnitt
58     gehen, "Eine einfache Anwendung mit PApp".
59    
60     H2: Applikationen statt Einzelseitenverwaltungsmonstren
61 root 1.1
62     Bei CGI oder anderen Schnittstellen ist die Sicht auf die Anwendung
63     protokollbedingt seitenbasiert - jede "logische" Seite ist eine Datei
64     oder eine Fallunterscheidung innerhalb der Datei - gemeinsame Komponenten
65     müssen in Bibliotheken (oder auch nur Include-Dateien; ist im Prinzip
66     das gleiche) abgelegt werden die auf jeder Seite erneut geladen,
67     konfigurietr und eingebaut werden müssen. Perl-Programme funktionieren
68     jedoch anders, da gibt es keine Zustände, die beim anklicken wechseln,
69     sondern ein lineares Programm. Dies läßt sich zwar auch mit PApp nicht
70     verwirklichen, aber es tut sein Bestes, diese Einschränkungen wegzuheben,
71     indem es ganze Anwendungen bearbeitet: Ob mehrere Seiten in einer Datei
72     oder eine Seite auf mehrere Dateien verteilt wird ist in PApp egal.
73    
74 root 1.2 H2: development/maintainance: Aktivposten statt Bremsklötzen
75 root 1.1
76 root 1.2 H3: Entwicklungshilfe
77 root 1.1
78 root 1.2 Programme - auch solche, die mit PApp geschrieben werden - müssen erst
79     entwickelt werden. Dabei werden Fehler gemacht. Da bei PApp sehr viele
80     Komponenten zusammenwirken können die Fehler entsprechend komplex
81     sein. Eine gute Unterstützung bei der Fehlersuche ist also wichtig.
82 root 1.1
83 root 1.2 Dies fängt damit an, dass die Zeilennummern des Quelltextes auch nach
84     der Kompilierung von Perl/XML zu reinem Perl oder z.B. in ein XSLT
85     erhalten bleiben. Sollte ein Fehler auftreten, so hat man sofort Zugriff
86     auf die Qeulldateien, einen kompletten Backtrace und natürlich die
87     State-Daten. Das Exception-System von PApp ist einfach zu benutzen (C<die>
88     genügt, will man es schöner haben benutzt man C<fancydie> ;) und
89     erweiterbar.
90 root 1.1
91 root 1.2 Im Betrieb will man natürlich keine ausführlichen Fehlermeldungen,
92     komplett mit Passwort der Datenbank usf... Deshalb protokolliert PApp
93     alle Fehler in eine SQL-Datenbank zusammen mit der State-ID, so dass
94     nur die Fehlerkategorie (plus ein nettes Textfeld, in dem der Benutzer
95     zusätzliche Informationen eingeben kann). Solange die Seite nur
96     wiederholbare Aktionen enthält, kann der Entwickler den Fehler jederzeit
97     reproduzieren.
98 root 1.1
99 root 1.2 H3: Datenbanken
100 root 1.1
101 root 1.2 Wie soll man ohne auskommen? Natürlich garnicht. In Perl gibt es ein ganz
102     wunderbares System (DBI!) um mehr-oder-weniger genormt auf SQL-Datenbanken
103     zugreifen zu können. Jetzt ist "nacktes" DBI recht umständlich,
104     zumindest für mich, für den vier Aufrufe pro SQL-Befehl entschieden zu
105     viel sind. Vor allem, wenn man diese über das Programm verstreuen muss.
106 root 1.1
107 root 1.2 In PApp erledigt man die meisten Aufgaben mit der C<sql_exec>-Funktion
108     (den Rest erledigt man mit C<sql_fetch/fetchall/exists/insertid>). Der
109     folgende Aufruf ersetzt C<prepare>, C<bind_params>, C<execute> und
110     C<bind_columns>:
111 root 1.1
112     !block perl
113 root 1.2 my $st = sql_exec \my($p, $w),
114     "select purzel, wurzel from table
115     where name like ?",
116     $S{search};
117    
118     while ($st->fetch) {
119     echo "$p, $w\n";
120     }
121 root 1.1 !endblock
122    
123 root 1.2 Der besondere Clou: Die SQL-Statements werden gecached, d.h. im
124     Allgemeinen nur ein einziges mal C<prepare>d. Bei Datenbanken, die einiges
125     an Aufwand in diesem Schritt investieren (Stichwort Query-Optimizer)
126     ist das ein grosses Plus. Sogar bei Datenbanken, die dies nicht tun
127     (z.B. MySQL) steigt die Geschwindigkeit merklich. Zudem sind das
128     C<prepare> und das C<execute> in normalen Programmen getrennt voneinander
129     (die Befehle stehen weit auseinander).
130 root 1.1
131 root 1.2 Bei Datenbanken, die eine Art "insertid" unterstützen (zum Glück fast
132     alle), kann man diese nach einem C<INSERT> gleich mit abfragen:
133 root 1.1
134     !block perl
135 root 1.2 my $id = sql_insertid
136     sql_exec "insert into tiere (name) values (?)",
137     "hase";
138 root 1.1 !endblock
139    
140 root 1.2 Den Database-Handle habe ich übrigens nicht vergessen: Wenn ich
141     keinen angebe, wird ein Default-Handle benutzt. Geschickterweise wird
142     dieser von PApp selbst gesetzt, so dass man sich im Normalfall noch
143     nicht einmal um die Datenbankverbindung kümmern muss (weil diese auf
144     dem Produktionssystem meistens andere Passwörter hat als auf dem
145     Entwicklungssystem stellt man diese geschickterweise bei der Konfiguration
146     der Applikation ein).
147 root 1.1
148 root 1.2 <<admin.png>>
149 root 1.1
150 root 1.2 H2: Trennung von Quelltext und Sprache
151 root 1.1
152 root 1.2 H3: XML
153 root 1.1
154 root 1.2 XML wird in mehreren Teilen von PApp unterstützt bzw. gefordert: Der
155     Standard-Dialekt von PApp ist in XML geschrieben, d.h. um "normale"
156     PApp-Applikationen zu schreiben muss man sich XML bedienen. Die Ausgabe
157     von PApp (meistens Text) ist beliebig, sofern man keine Stylesheets
158     benutzt. Tut man das, muss die Ausgabe natürlich in XML-Syntax sein. Und
159     last-not-least gibt es ein PApp-Modul, mit dem man beliebige XML-Fragmente
160     mit eingebettetem Perl-Quelltext bearbeiten/ausführen/anzeigen kann.
161 root 1.1
162 root 1.2 Die Entscheidung, XML so zentral einzusetzen, fiel mir nicht
163     leicht: Meiner Meinung nach ist XML wunderbar dafür geeignet,
164     Daten innerhalb von Programmen zu verarbeiten und vor allem
165     auszutauschen. Toll ist, dass Menschen XML notfalls lesen und auch
166     schreiben können. Ansonsten ist doch die Mächtigkeit von SGML (oder
167     etwas anderem) vorzuziehen.
168 root 1.1
169 root 1.2 XML jedoch hat bestechende Vorteile: HTML ist eine XML-Applikation (und
170     HTML ist wichtig ;); es existiert eine breite Unterstützung für XML;
171     es gibt bestehende Standards für Stylesheets, Layout, Metadaten und
172     mehr. Schliesslich ist XML auch noch sehr schnell. Nun ja.
173 root 1.1
174 root 1.2 Das hat mich trotzdem nicht davon abgehalten, etwas oben
175     draufzusetzen: Fast alle Dokumente können in einem "Meta-Format" mit
176     eingebettetem Perl-Quelltext geschrieben werden. Die Standard-Syntax
177     dafür bedient sich vier sog. "Modus-Umschalter", die jeweils vom
178     "Verbatim" in den "Perl"-Modus bzw. zurück schalten:
179 root 1.1
180     !block verbatim
181 root 1.2 <: schalte von HTML in Perl um
182     <? wie <:, füge jedoch das Ergebnis in die Ausgabe ein
183    
184     :> schalte in den HTML-Modus
185     ?> schalte in den interpolierten HMTL-Modus
186 root 1.1 !endblock
187    
188 root 1.2 Diese Modus-Umschalter habe ich in den Beispielen schon verwendet, z.B.
189     kann man eine HTML-Seite so schreiben:
190 root 1.1
191 root 1.2 !block perl
192     <h1>Ein bisschen HTML</h1>
193     <: echo "mit eingebautem perl" :>
194     <: print "so gehts auch, ist aber unendlich wenig langsamer ;)" :>
195     <?"So gehts am schnellsten":>
196     <:for my $text (qw(Noch eine komische Methode)) {
197     ?>$text&#160;<:
198     }:>
199     !endblock
200 root 1.1
201 root 1.2 Die Modus-Umschalter verhalten sich dabei wie eine Statement-Grenze in Perl (also C<;>).
202 root 1.1
203 root 1.2 H3: I18n
204 root 1.1
205     I18n steht kurz für Internationalisierung: Das englische Wort
206     {{Internationalization}} hat 18 Buchstaben zwischen dem 'I' und dem
207     'n', und da das Wort für den Durchschnittsamerikaner viel zu lang und
208     kompliziert ist, hat man diese 18 Buchstaben einfach durch "18" ersetzt.
209    
210     In Kontext von PApp bedeutet dies, dass beinahe überall Textmeldungen
211     übersetzt werden können (wer das C<gettext>-Paket kennt, mit dem
212     üblicherweise C-Programme internationalisiert werden, wird sich fast
213     sofort Zuhause fühlen). Hier ist ein Beispiel:
214    
215     !block verbatim
216     <h1>__"Contents"</h1>
217     <:for (1..10) {:>
218     <?slink sprintf(__"Chapter %d", $i++),
219     "view_chapter", chapterid => $i:>
220     <:}:>
221     !endblock
222    
223     Wie man sieht, kann man C<__"text"> sowohl im
224     HTML/XML/wasauchimmer-Quelltext benutzen, als auch auf Perl-Ebene
225     aufrufen. Die C<__>-Funktion erledigt dabei zwei Aufgaben: Zunächst werden damit
226     Textkonstanten zum übersetzen {{markiert}}. Zur Laufzeit wird dann in der Übersetzungstabelle nachgesehen und
227     der (evt.) übersetzte String zurückgeliefert.
228    
229     Wenn man Daten z.B. aus einer Datenbank in eine Variable holt, darf man diese natürlich {{nicht}} markieren, da sie ja nur zur Laufzeit einen String {{enthält}}, selbst
230     aber keine Textkonstante ist. In solchen Fällen verwendet man C<gettext>:
231    
232     !block perl
233     my $st = sql_exec \my($id, $name), "select id, name from table";
234    
235     while ($st->fetch) {
236     echo "<li>", gettext$name, "</li><br/>";
237     }
238     !endblock
239    
240     In welche Sprache jeweils übersetzt wird, entscheidet bei HTTP die
241     Einstellung des Browsers, wobei man zweckmässigerweise ein Menü
242     anbietet, in dem der Benutzer dies überschreiben kann:
243    
244     !block perl
245     <?slink "I want English", SURL_SET_LANG => "en":>
246     <?slink "Deutsch willich!", SURL_SET_LANG => "de":>
247     !endblock
248    
249     Auch die Spracheinstellung ist eine Preferences-Variable. Im Gegensatz
250     zum C<gettext>-Paket müssen die Quelltext nicht alle in einer Sprache
251     sein. Bei C<gettext> ist das auch weniegr ein Problem, da der Quellcode
252     eines Programms meistens in einer (natürlichen) Sprache geschrieben
253     wurde, in PApp kann man aber Seiten dynamisch einfügen oder Datenbanken
254     übersetzen. Da diese meist nicht vom selben Team geschrieben werden, ist
255     es nützlich, dort unterschiedliche Sprachen verwenden zu können.
256    
257     <<poedit1.png>>
258     <<poedit2.png>>
259    
260 root 1.2 H3: Unicode / Zeichensatzunabhängigkeit
261 root 1.1
262     Intern unterstützt PApp genau zwei Datentypen (genau wie Perl
263     selbst): {{Binärdaten}} und {{Text}}. Binärdaten verwendet man
264     üblicherweise für Bilder, Datei-Downloads und ähnliches. Diese Daten
265     werden von PApp nicht angerührt.
266    
267     Ganz anders Text: Perl arbeitet intern mit Unicode, das z.Zt. entweder in
268     ISO-8859-1 oder UTF-8 gespeichert wird. Dieser interne Zeichensatz ist
269     völlig unabhängig von der Ausgabe, d.h. der Text wird bei der Ausgabe
270     automatisch in den gewünschten Zeichensatz kodiert (das geschieht wieder
271     Browser/Benutzer/Programmabhängig wobei von den gebräuchlichen Browsern
272     nur Netscape und Lynx die entsprechenden Header liefern). Umgekehrt werden
273     Formulardaten u.ä. automatisch in Unicode gewandelt, d.h. in C<%P> steht
274     Unicode auch wenn der Browser ein Formular in ISO-2022-JP zurückgeschickt
275     hat.
276    
277     Ein JPEG-Bild kann man z.B. so ausgeben:
278    
279     !block perl
280     content_type "image/jpeg", undef;
281     $gd->jpeg(80);
282     !endblock
283    
284     Während man eine japanische Benutzerin vielleicht mit ISO-2022-JP
285     zufriedenstellen kann:
286    
287     !block perl
288     content_type "text/html", "iso-2022-jp";
289     echo __"Hoffentlich war der Übersetzer fleissig";
290     !endblock
291    
292 root 1.2 H2: Trennung von Daten und Layout/Protokoll
293 root 1.1
294 root 1.2 Sprache und Quelltext trennt PApp ja schon. Jetzt muss man noch das Layout
295     vom eigentliche Programm bzw. das Protokoll von den eigentlichen Daten
296     trennen.
297    
298     Mit XSLT-Stylesheets geht das. Und mehr: "Browser XYZ hat ein Problem? Ich
299     fix' es im Stylesheet und vergesse es dann einfach." (z.B. sollte man
300     leere HTML-Tabellenzellen für Netscape lieber mit einem C<&nbsp;>
301     füllen). "Es soll WML (oder CHTML) sein? Ich weiss zwar nicht, wozu
302     das ganze WML-Zeugs sinnvoll sein soll, aber dann mache ich halt' ein
303     Stylesheet dafür." Und eine der wichtigsten Anwendungen: "Wir brauchen
304     eine Version zum drucken. Dafür wandeln wir unser XML-Dokument in XSL" (und dann
305     nach Latex, PDF...).
306    
307     Das bedeutet, dass man - Planung natürlich vorausgesetzt - einen hohen
308     Grad an Protokollunabhängigkeit erreichen kann, ohne den Quelltext zu
309     sehr mit Layout-Entscheidungen o.ä. belasten zu müssen.
310    
311     Leider gibt es noch keine Web-Designer, die XSLT statt HTML/CSS liefern,
312     aber (meine) Vision des Webs der Zukunft sieht so aus: Der Server liefert
313     XML zusammen mit einem XSLT (vom Designer), welches XSL erzeugt. Dieses
314     wird dann angezeigt/gedruckt etc.a.. Metadaten (mit dem etwas besseren
315     Nachfolger von RDF) gestatten dann Fragen wie: "Wer hat dieses Dokument
316     geschrieben?", "Wozu dient es?" aber auch: "Wieso ist das Ding so bunt?".
317    
318     H2: Trennung von Funktionalität und Ausführungsumgebung
319    
320     Platform-Unabhängigkeit: ein toller Begriff. Was bedeutet er? Nicht
321     viel. Bei PApp bedeutet es, dass auf Unix-Abhängigkeiten möglichst
322     verzichtet wurde und sich PApp nicht an einen bestimmten Server
323     (z.B. Apache) bindet. In der Praxis kann man als Platform mod_perl
324     oder CGI verwenden und für Windoze schere ich mich einen Dreck. Aber
325     auch andere Umgebungen wie Text-Interfaces sind denkbar: Da PApp der
326     Applikation immer eine gleichbleibende Umgebung anbietet, muss man
327     lediglich ein Schnitstellenmodul schreiben.
328    
329     H2: Persistente Variablen für Sessions und User
330    
331     PApp kümmert sich automatisch um persistente Variablen. So kann man
332     automatisch Variablen erzeugen, die über eine gesamte Sitzung (die mit
333     dem Aufruf der ersten URL beginnt und dann einen Baum bildet) persistent
334     sind. Das geht so einfach, dass man spezielle Hilfsmittel braucht, um
335     nicht an jeder Stelle der Sitzung Zugriff auf beinahe alles zu besitzen.
336    
337     Persistente Variablen gibt es in verschiedenen Geschmäckern. Es gibt:
338    
339     - Session-Variablen (sogenannte {{state keys}}), die über eine gesamte
340     Sitzung erhalten bleiben. Diese werden im Hash C<%S> gespeichert. Man kann
341     beliebige Werte darin ablegen (solange C<Storable> diese serialisieren
342     kann). Meistens gescheiht dies durch Anklicken eines Links, weniger
343     häufig direkt.
344    
345     - Benutzerabhängige Variablen (die auch über Sitzungsgrenzen hinaus
346     erhalten bleiben und deshalb {{preferences items}}, Voreinstellungen,
347     heissen). Auch diese befinden sich in C<%S>, von wo sie automatisch in die
348     Benutzerdatenbank wandern bzw, von dort gelesen werden.
349 root 1.1
350 root 1.2 - Lokale Variablen ({{local keys}}) zu nur innerhalb einer Seite oder
351     einer Gruppe von Seiten Bedeutung haben. Diese befinden sich ebenfalls in
352     C<%S> und werden automatisch daraus entfernt.
353 root 1.1
354 root 1.2 - oder beliebige Kombinationen davon.
355 root 1.1
356 root 1.2 Ein Beispiel für eine Sitzungsvariable ist die Information, ob der
357     Benutzer sich schon angemeldet/eingeloggt hat oder ob er bestimmte
358     Zugriffsrechte besitzt. Eine benutzerabhängige Variable ist z.B.die
359     Sprache, die der Benutzer zuletzt ausgewählt hat (global) oder die
360     Anzahl der Tabellenzeilen, die der Benutzer gerne auf einer bestimmten
361     Seite angezeigt haben möchte. Eine lokale Variable ist z.B. ein
362     Datenbank-Objekt, das über mehrere Seiten (z.B. einer Transaktion)
363     gebraucht wird und danach seine Gültigkeit verliert.
364 root 1.1
365 root 1.2 Dadurch ergeben sich mehr Möglichkeiten, als man erwarten
366     würde: Unabhängige Komponenten (z.B. Werbebanner oder Foren) sind auf
367     normale Weise nur sehr schwer zu programmieren, da sie immer Hilfe vom
368     "Hauptprogramm" erfordern wenn es um die Parameterübergabe geht. In PApp
369     benutzt man einfach persistente Variablen.
370 root 1.1
371 root 1.2 Ein Beispiel für eine etwas ungewöhnlichere Komponente ist die
372     {{editform}}-Bibliothek. Mit ihr kann man HTML-Formulare erstellen, die
373     sich direkt an eine bestimmte Variable binden:
374 root 1.1
375 root 1.2 !block perl
376     ef_begin;
377     ef_string \$S{search};
378     ef_end;
379     !endblock
380 root 1.1
381 root 1.2 Dieses Beispiel stammt von einer Seite, die Objekte aus einer Datenabnk
382     anzeigt und sich dabei auf solche beschränkt, die ein Suchwort
383     enthalten. Das Formular bindet die State-Variable C<search> an ein
384     HTML-Textfeld. Bei der Ausgabe wird der aktuelle Wert von C<$S{search}>
385     benutzt. Ändert der Benutzer den Text und schickt das Formular ab wird
386     die Seite neu aufgebaut - mit einem anderen Wert in C<$S{search}>. Da
387     editform beliebige Perl-Referenzen akzeptiert und man in PApp auch
388     Referenzen auf Dateien, SQL-Spalten etc... erzeugen kann werden viele
389     Formulare zum Kinderspiel.
390 root 1.1
391 root 1.2 Zusätzlich zu den Sitzungsvariablen gibt es noch sogenannte
392     {{Argumente}}, die nur eine Seite lang "persistent" sind, d.h. bei einem
393     Link auf eine andere Seite übergeben werden:
394 root 1.1
395 root 1.2 !block perl
396     echo slink "Klicken Sie hier", -argument1 => "wert1", var2 => "wert2";
397 root 1.1 !endblock
398    
399 root 1.2 Wenn man diesem Link folgt, steht der "wert1" im Hash C<%A> bzw. "wert2"
400     im Hash C<%S>:
401 root 1.1
402     !block perl
403 root 1.2 printf "Das Argument argument1 ist %s, die State-Variable var2 ist %s",
404     $A{argument1}, $S{var2};
405 root 1.1 !endblock
406    
407 root 1.2 Werte, die von "Aussen" (z.B. GET-Request in CGI) kommen, stehen, um die
408     Verwirrung komplett zu machen, in C<%P>. Als Faustregel gilt: was in C<%S>
409     und C<%A> steht ist sicher (bzw. man hat es selbst dorthin gepackt), was
410     in C<%P> steht ist unsicher und muss erst gefiltert/geprüft werden.
411    
412     H2: Sicherheit
413    
414     In vielen CGI-Programmen (aber nicht nur dort) wird der Fehler
415     begangen, sensitive Daten in {{hidden}}-Feldern in einem Formular zu
416     "verstecken" oder sie in die URL zu kodieren um die Parameterübergabe zu
417     realisieren. Dies ist in PApp nicht nötig, da der persistente 'State' in
418     einer Datenbank gespeichert wird und nur der (mit 256 Bit verschlüsselte)
419     Zeiger darauf zum Client übertragen wird. Dadurch werden sensitive Daten
420     gar nicht erst zum Client übertragen, was natürlich auch Bandbreite
421     spart. Sollte der Schlüssel einmal bekannt werden kann man zwar auf
422     andere Sessions zugreifen, die Daten jedoch immer noch nicht verändern
423     (dieser Fall tritt beispielsweise auch auf, wenn ein kaputtes Proxy
424     zwischen Server und Client sitzt).
425    
426     Eine typische PApp-URL sieht übrigens so aus (Applikation "kis", Modul
427     "abteilungswahl"):
428 root 1.1
429 root 1.2 !block verbatim
430     /kis/abteilungswahl/NIlRSJNDIfP3AHfVjxLF5F
431     !endblock
432 root 1.1
433 root 1.2 Da eine "Seite" in PApp aus einem Modulbaum besteht, geht es auch
434     komplizierter:
435 root 1.1
436 root 1.2 !block verbatim
437     /admin/+admin=poedit+poedit=view--?papp=eTDgL.I-lj9O9lTO3wznTk
438     !endblock
439 root 1.1
440 root 1.2 Zusammen mit einem sicheren Transportprotokoll (z.B. SSL, wobei die
441     meisten Browser nur ungenügend oder garnicht gegenüber Attacken
442     schützen, nur so am Rande ;) schützt man sich damit gegen alle Seiten.
443     Benutzerauthentifizierung über Zertifikate ist auch im Einsatz (mit dem
444     C<ssl>-Modul von PApp).
445 root 1.1
446 root 1.2 H2: Session/User-tracking
447 root 1.1
448 root 1.2 Persistente Variablen erfordern Session-Tracking. Benutzerabhängige
449     Einstellungen (Preferences) darüber hinaus auch User-Tracking. Ersteres
450     geschieht mit einer Session-ID, die (auf verschiedene Arten) in die
451     URL-kodiert wird und die alle notwendigen Daten enthält, um die
452     gewünschte Seite komplett zu erzeugen. Darüber hinaus wird (optional)
453     ein Cookie benutzt, das aber z.Zt. nur zum Identifizieren des Benutzers
454     dient, da ich Session-Definitionen per Cookie als Unsinn erachte. Das
455     Cookie wird auch nur einmal am Tag gesetzt, so daß man auch mit der
456     Browser-Einstellung "vor Cookies warnen" arbeiten kann.
457 root 1.1
458 root 1.2 Eine Anwendung wird darüber informiert, ob eine neue Session begonnen
459     wurde oder ob sich ein bisher unbekannter Benutzer angemeldet hat, so
460     daß man Benutzereinstellungen o.ä. initialisieren kann. Dies nützt
461     PApp selbst, um sich z.B. die Sprache des Benutzers zu merken oder um das
462     User-Cookie nur einmal täglich zu setzen.
463 root 1.1
464 root 1.2 Eine "Sitzung" ist übrigens ein Baum (nicht nur in PApp), der mit dem
465     ersten "Hit" als Wurzel beginnt. Dadurch ist es unter anderem möglich,
466     die Anzahl der "Reloads" einer Seite zu bestimmen. Dies ist nützlich,
467     um potentiell gefährliche Aktionen (z.B. Löschen von Datenbanken,
468     abschicken von E-mails) nur einmal auszuführen.
469 root 1.1
470 root 1.2 H2: Benutzerverwaltung
471 root 1.1
472 root 1.2 Da PApp Benutzer (mehr oder weniger) eindeutig identifizieren muss,
473     implementiert es intern eine eigene Benutzerverwaltung inklusive einer
474     Unix-artigen Rechtevergabe (es gibt allerdings keinen Super-User im
475     Unix-Sinne). In vielen Anwendungen kann man diese gleich mitbenutzen, da
476     eine eindeutige Benutzer-ID automatisch vergeben wird.
477 root 1.1
478 root 1.2 !block verbatim
479     Sie sind wahrscheinlich Benutzer Nummer <?$userid:><br/>
480     #if auth_p
481     Und ausserdem haben sie sich authentifiziert.<br/>
482     # if access_p "admin"
483     Oh, und "admin"-Rechte besitzen Sie auch noch! Meine Güte!!<br/>
484     # endif
485     #endif
486 root 1.1 !endblock
487    
488 root 1.2 H2: Geschwindigkeit und Skalierbarkeit
489 root 1.1
490 root 1.2 Geschwindigkeit war bei der Implementierung von PApp das zweitwichtigste
491     Ziel (Korrektheit ist das wichtigste ;). Als Marke dient mir ein
492     Pentium-II 266Mhz-Rechner, auf dem auch komplexe Seiten mit mindestens 15
493     Hits/Sekunde dargestellt werden, bzw. der Vergleich mit einem ähnlichen
494     C<Apache::Registry>-Skript.
495 root 1.1
496 root 1.2 Das State-Management von PApp verschlingt pro Seite 1-3 Datenbankzugriffe,
497     die die Zeit bei weitem dominieren (andere Features wie I18n sind im
498     Prinzip kostenlos). Da komplexe Seiten im Allgemeinen wesentlich mehr und
499     kompliziertere Zugriffe enthalten bzw. man ja irgendwie seine Daten
500     speichern muss, ist dies in der Praxis selten eine Einschränkung
501     (Ausnahmen gab und gibt es immer). Andere PApp-Features (z.B. im
502     SQL-Bereich) bringen häufig sogar eine Steigerung der Geschwindigkeit.
503 root 1.1
504 root 1.2 Da ich bisher keine Seite fabrizieren konnte, die die 15 Zugriffe/s-Marke
505     unterschritten hätte, glaube ich noch etwas Spielraum für noch mehr
506     Features zu haben. Wer sich übrigens fragt, woher diese 15 Hits/s
507     kommen: 15 Hits ist die Marke, die einen wirklich grossen Server von den
508     99.99% der restlichen Welt unterscheidet. Hat man auf seinem Server 15
509     oder mehr Zugriffe pro Sekunde kann man sich meistens auch eine schnellere
510     Datenbank oder mehrere Rechner leisten: PApp skaliert problemlos auf
511     mehrere Maschinen.
512 root 1.1
513 root 1.2 H2: Ideen, Ideen: z.B. "tied forms"
514 root 1.1
515     Ich habe es schon angesprochen: Persistenz von fast allem, zusammen mit
516     den Möglichkeiten von Perl können einen schon auf Ideen bringen, z.B.
517     auf eine Bibliothek (editform), die HTML-Formularfelder an Perl-Refrenzen
518     bindet.
519    
520     Nun ist es an der Zeit, einmal eine Referenz auf eine SQL-Tabelle zu
521     erzeugen:
522    
523     !block perl
524     <:
525     my $row = new PApp::DataRef 'DB_row',
526     table => "user",
527     where => [id => $userid],
528     delay => 1,
529     autocommit => 1;
530    
531     # pre-set name
532     $row->{name} ||= "<username>";
533    
534     ef_begin;
535     :><br>__"ID:" <?ef_string \$row->{id} , 5:><:
536     :><br>__"Name:" <?ef_string \$row->{name}, 20:><:
537     ef_submit __"Update";
538     ef_end;
539     :>
540     !endblock
541    
542     Die Referenz auf die Zeile steht in C<$row> un verhält sich wie eine
543     Referenz auf einen herkömmlichen Perl-Hash. Das C<autocommit> sorgt
544     dafür, dass die geänderten Daten automatisch zurückgeschrieben werden
545     sobald das C<$row>-Objekt gelöscht wird (ausser Scope geht, C<DESTROY>ed
546     wird). Sie ist lokal (C<my>!) gespeichert, da aber die C<ef_>-Funktionen
547     die Referenz persistent speichern, wird das Objekt erst auf der nächsten
548     Seite (also nachdem die Ergebnisse hineingeschrieben wurden!) zerstört,
549     bzw. die Daten geschrieben. Etwas kompliziert, aber zum Benutzen muss man
550     die Details ja auch nicht kennen.
551    
552     Nun macht das Beispiel keine Fehlerüberprüfung, meistens das
553     schwierigste. Mit PApp kein Problem. Zuerst schalten wir das C<autocommit>
554     ab, damit die Daten nicht "aus Versehen" geschrieben werden. Ausserdem
555     übergeben wir die Referenz als Argument an die "nächste" Seite.
556    
557     !block perl
558     <:
559     my $row = $A{row}
560     || new PApp::DataRef 'DB_row',
561     table => "user",
562     where => [id => $userid],
563     delay => 1,
564     autocommit => 0;
565    
566     ef_begin -row => $row; # Daten als Argument übergeben
567     !endblock
568    
569     Nun brauchen wir ein Flag, das uns sagt, ob der Datensatz fehlerhaft ist
570     und schon können wir loslegen:
571    
572     !block perl
573     my $err = 0; # Daten fehlerhaft?
574    
575     :><br/>__"ID:" <?ef_string \$row->{id} , 5:><:
576     #if $row->{id} !~ /^(\d+)$/
577     <error>__"The ID must be an integer!"</error>
578     <:$err++:>
579     #endif
580     :><br/>__"Name:" <?ef_string \$row->{name}, 20:><:
581     #if 2 > length $row->{name}
582     <error>__"The Name must contain at least two characters!"</error>
583     <:$err++:>
584     #endif
585     ef_submit __"Update";
586     ef_end;
587     !endblock
588    
589     Die Daten schreibt man dann bei Bedarf in die Datenbank:
590    
591     !block perl
592     #if $row->dirty
593     # if $err
594     <error>__"The entered Data is invalid, please surrender or die (or correct it ;)</error>
595     # else
596     <:$row->flush:>
597     __"The record has been updated."
598     # endif
599     #endif
600     :>
601     !endblock
602    
603     H2: "Web-Widgets"
604    
605 root 1.2 Eine relativ neue "Neuerung" in PApp ist die Einführung von
606     Web-Widgets. Wie so vieles sind das keine speziellen Objekte, sondern eine
607     Art der Programmierung, die zwar schon immer möglich warm aber an die man
608     nicht sofort denkt.
609    
610     Statt einer ganzen Applikation, die "ganze Seiten" (z.B. ganze
611     HTML-Seiten) ausgibt, schreibt man eine Applikation, die nur noch
612     Teilseiten ausgibt, die man in größere Applikationenn einbaut. Dies ist
613     nicht das gleiche wie ein "include": Der Namensraum (globale Variablen,
614     state-keys, also Session-Variablen und Preferences) einer solchen
615     eingebetteten Applikation ist getrennt von der einbettenden Anwendung und
616     bildet eine Art "Unternamensraum".
617    
618     Derlei eingebettete Anwendungen sind vollkommen autark, haben ihren
619     eigenen Zustand ("aktuelle Seite") und können ihre eigenen Formulare,
620     Links etc. erzeugen die mit anderen Applikationen nicht kollidieren. In
621     einer Anwendung verwende ich dasselbe Forum-Element, um "Web Chat",
622     "Kleinanzeigen" und eine "News!"-Seite zu implementieren - jedesmal eine
623     leicht andere Konfiguration aber derselbe Code.
624    
625     Da PApp-Applikationen im Prinzip nur grosse Statemaschinen sind (das ist
626     eine Einschränkung der verwendeten Protokolle, d.h. bis Perl effektive
627     und schnelle continuations bekommt ;), kann man sie auch einfach in andere
628     einbauen. Sie können sich gegenseitig beeinflussen, treten sich aber
629     nicht auf die Füsse.
630    
631     Also im Prinzip genauso wie ein "Widget" unter X11.
632    
633     H2: Logging/Protokollierung
634    
635     PApp protokolliert wesentlich mehr, als man benötigt, legal wäre, und
636     speicherbar wäre. Da PApp jederzeit in der Lage sein muss, eine ältere
637     Seite zu regenerieren ("Back & Reload"), speichert es pro Seite die
638     persistenten Variablen (ca. 300-900 Byte, je nach Applikation, das ist,
639     wie gesagt, auch eine tolle Sache zum Debuggen).
640    
641     Aber irgendwann müssen diese Daten wieder weg bzw. statistische Daten
642     her - nichts ist interessanter, als Zugriffsmuster, Voreinstellungen oder
643     ähnliches, an dem man ablesen kann, welche Dinge beliebt sind und welche
644     nicht (klar, man kann auch ganz andere Sachen auswerten, aber das ist
645     nicht mein Problem).
646    
647     Beim Aufräumen spielt PApp die einzelnen Zugriffe noch einmal
648     durch. Statt jedoch Seiten zu erzeugen gibt PApp den einzelnen
649     Applikationen die Möglichkeit, statistische Daten zu sammeln. Etwas
650     undokumentierter (wenn es da Abstufungen gibt) ist die Möglichkeit,
651     globale Daten zu sammeln, aber es geht...
652 root 1.1
653 root 1.2 H1: Eine einfache Anwendung mit PApp
654 root 1.1
655     What does it look like?
656    
657     %font "t", prefix " "
658     <package name="dunno"> <domain lang="en">
659    
660     <language lang="en" desc="English"/>
661     <language lang="de" desc="Deutsch"/>
662    
663     <database dsn="DBI:mysql:dunnodb"/>
664     <translate fields="project.name place.name"
665     lang="en"/>
666     <translate fields="project.description"
667     lang="mixed" style="auto"/>
668    
669     <import src="macro/util"/>
670    
671     <module src="dunno/somepages"/>
672    
673     </domain> </package>
674    
675     %page
676    
677     Modules
678    
679    
680     PApp is application centric - one application can consist of many pages (called 'modules').
681    
682     Each web-page is (usually) a seperate module.
683    
684     Modules and even applications can be nested or embedded.
685    
686     State keys can be shared with ease within a session or user context.
687    
688     One module == one state of the state machine (http and wap are statemachines!).
689    
690     %page
691    
692     A simple module
693    
694    
695     %font "t", prefix " "
696     <module name=""><phtml><![CDATA[
697     <html> <title>
698     __"PApp - demo", <?localtime:>
699     </title>
700    
701     <?slink "English", "/lang" => 'en':>
702     <?slink "Deutsch", "/lang" => "de":>
703    
704     <p><?slink __"To the editor", "editor":>
705     <p><?slink __"Edit project 1", "editor",
706     projectid => 1:>
707    
708     </html>
709     ]]></phtml></module>
710    
711     %page
712    
713     phtml mode switches
714    
715    
716    
717     <: switch to perl statement mode
718    
719     <? evaluate perl expression
720    
721     :> switch to plain html/text mode
722    
723     ?> switch to interpolated (qq) html/text mode
724    
725    
726     %page
727    
728     Another simple module - "editor"
729    
730    
731     %font "t", prefix " "
732    
733     <module name="editor">
734     <state keys="projectid" local="yes"/>
735     <phtml><![CDATA[
736     <:header:>
737    
738     #if defined $S{projectid}
739     ... edit the specific project
740     #else
741     ... show a list of projects
742     #endif
743    
744     <:footer:>
745     ]]></phtml></module>
746    
747     %page
748    
749     SQL support - the project list
750    
751    
752     %font "t", prefix " "
753     <table><tr><th>__"Project"<th>__"Budget"
754     <:
755     my $st =
756     sql_exec \my($id, $name, $budget),
757     "select id, name, budget
758     from project";
759    
760     while ($st->fetch) {
761     :><tr><td>
762     <?slink gettext$name,
763     projectid => $id?>
764     <td>$budget
765     <:
766     }
767     :>
768     </table>
769    
770     %page
771    
772     SQL support - persistent rows
773    
774     %font "t", prefix " "
775     <:ef_begin:>
776    
777     <:my $row = new PApp::DataRef 'DB_row',
778     table => "project",
779     where => [id => $S{projectid}]:>
780    
781     <p>__"Name":
782     <:ef_string \$row->{name}, 40:>
783     <p>__"Budget":
784     <:ef_string \$row->{budget}, 8:>
785     <p>__"Description":
786     <:ef_text \$row->{description}, 60, 10:>
787    
788     <:ef_submit __"Update":>
789     <:ef_end:>
790    
791     %page
792    
793     Internationalization (I18n)
794    
795    
796    
797     Strings inside source files can be "tagged"
798    
799     Database columns can be tagged
800    
801     PApp is unicode-only
802    
803     Output conversion (e.g. utf8>latin1, utf8>iso2022jp)
804    
805     Translation editor ("poedit") included
806    
807     %page
808    
809     Speed
810    
811    
812    
813     Speed is slightly worse than Apache::Registry - on simple pages!
814    
815     Complex pages usually make no difference (database overhead!)
816    
817     Many PApp features deliver a performance that would be tedious to match in plain perl!
818    
819     PApp scales to many server machines, if necessary
820    
821     %page
822    
823     XML
824    
825    
826     No, XML is not a feature.
827    
828     XML might be nice to computers, it isn't usually for humans, though.
829    
830     XML is robust
831    
832     XML is fast
833    
834     XML is well supported
835    
836     %page
837    
838     XML + XSLT = protocol independency
839    
840    
841     PApp can support XML as well as HTML
842    
843     You can write your pages in XML
844    
845     XSLT stylesheets can be applied
846     at parse time
847     before module execution
848     to the resulting output
849    
850    
851     Thus, PApp applications can easily be made protocol-independent by writing them in XML and using a stylesheet that outputs either HTML, XML, WML or whatever you like!
852    
853     %page
854    
855     Dynamic stylesheet example
856    
857     %font "t", prefix " "
858     <perl><![CDATA[
859     $stylesheet[0] =
860     $papp->load_stylesheet("dunno1");
861     $stylesheet[1] =
862     $papp->load_stylesheet("dunno2");
863     ]]></perl>
864    
865     <style apply="output"
866     expr="$stylesheet[ $S{style} ]">
867    
868     <module name=""><phtml><![CDATA[
869     <p/><?slink __"To the edito...
870     <p/><?slink __"Edit projec...
871     ]]></phtml></module>
872    
873     ...
874     </style>
875    
876     %page
877    
878     "Web-Widgets"
879    
880    
881     A nice term - what is it?
882    
883    
884     PApp applications can be "embedded" into host applications
885    
886     With careful coding, reusable objects be created (e.g. a forum module, an ad-banner module etc.)
887    
888     Embedded apps come with their own state machine, own environment etc.
889    
890     Apply stylesheets to customize, if necessary
891    
892     %page
893    
894     PApp
895    
896    
897    
898    
899    
900     seperates
901    
902     layout
903     semantics
904     language
905    
906     from each other!
907    
908     %page
909    
910     Disadvantages
911    
912    
913     perl 5.7.0 + patches is currently required
914    
915     many modules are necessary
916    
917     mod_perl is currently the only supported platform
918    
919     written by one overworked person only
920    
921     the api is in flux
922    
923     no stable release yet
924    
925     %page
926    
927     More info
928    
929    
930    
931    
932    
933    
934    
935    
936 root 1.2
937     Dabei ist PApp etwas sehr persönliches - ich habe meine persönlichen
938     Vorstellungen davon, wie Web/CGI etc. funktionieren sollte, darin
939     verwirklicht. Es hat meine Motivation (die sich mit "nie wieder CGI"
940     zusammenfassen liess) gewaltig gesteigert - Ein einfaches aber dennoch
941     komplettes Content-Management-System kann man in weniger als 500 Zeilen
942     hinlegen - für mich ein wichtiger Faktor, denn ich hasse nichts mehr, als
943     das Rad jedesmal neu erfinden zu müssen.
944    
945     H2: PApp is Free Software
946    
947     Although we are not sure wether we'll publish all versions of PApp
948     under the GPL, or which modules from our own applications might become
949     standard components (like the forum), we are determined to make PApp free
950     software. The principal PApp architect (me!) did a lot of free software
951     modules and works at quite a few free software programs (like GCC or The
952     Gimp) and is determined to make PApp as free and as powerful as possible.
953    
954     H1: Disadvantages
955    
956     PApp is not actually a revolution, judged by its components. It
957     does, however draw a lot of functionality and ideas into a single,
958     well-contained package. Nevertheless, there are quite a few reasons on why
959     {{NOT}} to use PApp, or at least not to use PApp {{YET}}.
960    
961     * PApp is not yet a released module, its API is in flux (with respect to
962     recent features), and not everything is working as it should yet. This
963     is fortunately only a question of time.
964    
965     * Only a single person is currently developing and designing PApp for
966     free. This means that advances might sometimes not lead into the
967     direction you want, and maybe not in the schedule you want.
968    
969     * PApp requires the very latest perl - at the moment, this is perl
970     5.7 + custom patches, due to the buggy unicode support in earlier
971     versions. The latest released PApp module (on CPAN) does not rely on
972     unicode, but is already quite outdated with respect to current features.
973    
974     * There is a total lack of tutorials or introductory courses. While all
975     PApp modules are documented, it is very much impossible to learn it
976     using the reference documentation alone. Basically a one-day course
977     under four eyes is necessary to get you up and running - PApp is
978     not trivial. The lost time is generally made up with the increase in
979     productivity experienced with PApp, though, similar to learning Perl ;)
980    
981     A1: References
982    
983     * PApp is available as a standard module from CPAN, although the current
984     version uploaded is very old.
985    
986     * The PApp homepage is available at the author's homepage, under
987     {{URL:http://www.goof.com/pcg/marc/papp.html}}. This page includes
988     links to the current manpages. Online demos are, unfortunately, not yet
989     available.
990    
991     * The newest versions of PApp can be accessed using CVS as a sourceforge project,
992     at {{URL:http://www.sourceforge.net}}.
993    
994     * The slides for this presentation will be available at the author's
995     homepage, at {{URL:http://www.goof.com/pcg/marc/docs.html}}, shortly
996     after the linuxworldexpo.
997    
998     A2: Apology
999    
1000     I'd like to apologize for any typoes or other mistakes in this
1001     document. It was written in a single session without access to a
1002     spellchecker and so has not been debugged it yet ;)
1003     %page
1004 root 1.1