baseportal | ||
Start | ||
baseportal beta2 - Dokumentation |
Rechte | Nach oben |
In vielen Fällen reicht es völlig aus, die Rechte für unangemeldete Nutzer zu bestimmen. Sie selbst, als Eigner haben immer alle Rechte an der Datenbank, ebenso der Programmcode, den Sie in Ihren Templates verwenden: Die dort verwendeten Funktionen können beliebig auf Ihre Datenbanken zugreifen.
Es gibt 4 Zugriffsarten, die beliebig kombiniert werden können:
Beispiele:
|
Um einen ausgefeilteren Schutz zu realisieren, bietet baseportal Nutzerdatenbanken an. In diesen ist verzeichnet, wer welchen Zugriff auf welche Felder welcher Datenbank hat. Sie können für jede Datenbank eine eigene Nutzer-Datenbank erstellen oder auch eine Nutzer-Datenbank für mehrere Datenbanken einsetzen.
Eine einfache Nutzerdatenbank könnte so aussehen:
Die Nutzer sepp und liese können lesend und schreibend auf die Datenbank zugreifen; der Nutzer gregor kann zusätzlich ändern und löschen. ALLE ist ein spezieller Nutzername...
Der Nutzername ALLE (komplett gross geschrieben!) hat, ebenso wie ANDERE eine besondere Bedeutung:
Name | Bedeutung |
---|---|
ALLE | Die Rechte die unangemeldete Nutzer haben |
ANDERE | Die Rechte die andere baseportal-Nutzer haben. Damit können Sie anderen baseportal-Nutzer direkten Zugriff auf Ihre Datenbanken geben, so dass diese auch in deren Templates genutzt werden können. ((noch nicht eingebaut)) |
ALLE bestimmt damit die allgemeinen Rechte, die oben beschrieben wurden, in einer Nutzer-Datenbank. Ein "Passwort" und ein Eintrag beim "EMail"-Feld erübrigt sich damit natürlich.
...
Bei komplexeren Rechten wäre es sehr mühsam bei vielen verschiedenen Nutzern diese immer wieder neu eingeben zu müssen. Beispiel: Sie haben interne Mitarbeiter definiert, die Zugriff auf die Felder "Name", "Strasse" und "Ort" haben. Später ergibt sich, dass sie auch noch das Feld "Telefon" lesen dürfen - nun müssten Sie bei jedem einzeln die Änderung durchführen.
baseportal bietet dafür eine bessere Lösung: Wie man am Beispiel sieht, kann man Nutzern bestimmte "Rollen" zuteilen und über diese Rollen ergeben sich dann die Rechte - so haben z.B. alle News-Redakteure das Recht zu schreiben.
Innerhalb der Datenbank ist eine Rolle nichts anderes als ein Nutzer. Obwohl nicht zwingend, ist es keine schlechte Idee, Rollen immer komplett gross zu schreiben, um sie so einfach von normalen Nutzern unterscheiden zu können. Auch die speziellen Nutzernamen ALLE und ANDERE fügen sich so ins Bild, denn sie sind, wenn man so will, ebenfalls Rollen.
Es können auch mehrere Rollen, durch Komma getrennt angegeben werden. Ein Nutzer erhält dann alle Rechte der einzelnen Rollen zusammen. Es werden auch die bei den Rollen angegebenen Rollen weiterverfolgt (bis maximal 50), so dass eine komplexe Rechtehierarchie aufgebaut werden kann.
|
Hier eine kleine, aber feine Nutzerdatenbank mit verschiedenen Rollen:
Unangemeldete Besucher dürfen das Feld "Name" lesen, sonst nichts. MITARBEITER dürfen die Felder "Name", "Strasse", "Ort" und "Telefon" lesen, in diesem Fall haben diese Rolle die Nutzer berger und krumpawesch. Letzterer hat zusätzlich die Rolle EINGEBER, d.h. er darf auch komplette Einträge (in alle Felder) machen. Die Nutzerin gabi hat die Rolle KONTROLLEUR, mit der sie alle Felder lesen und Einträge löschen darf. Beim Nutzer fongi schliesslich werden die Rechte aus der Rolle KONTROLLEUR um das Recht, alle Felder zu ändern, ergänzt. Die Weitervererbung von Rechten sieht man am Nutzer Schlumpf, der die Rechte von KONTROLLEUR2 bekommt und zusätzlich die Rechte von KONTROLLEUR (die Rolle von KONTROLLEUR2).
|
<--- Sowohl bei den Feldern, als auch bei den Rollen sollte man auch Datenbanken bestimmen können, also z.b. "bugs(Name,Strasse),wishes(Name) - oder so... mhhh, oder anders?? aber irgendwie so... -->
Bei der Einrichtung einer Nutzerdatenbank gibt baseportal zwei verschiedene Typen zur Auswahl vor:
Typ | Felder | Kommentar |
---|---|---|
Einfach | Name, Passwort, EMail, Lesen, Schreiben, Ändern und Löschen | Die Rechte sind als "checkbox" definiert, damit vergibt man das Recht für alle Felder. Es gibt auch keine Rollen. In vielen Fällen reicht diese Nutzer-Datenbank völlig aus. |
Felder | Name, Passwort, EMail, Rollen, Lesen, Schreiben, Ändern, Löschen, Erstellt am und Gesperrt | Die Rechte sind als "text"-Felder definiert, d.h. ein Recht kann für bestimmte Felder vergeben werden. |
Hier die einzelnen Felder und ihre Funktionen:
Feld | Beschreibung |
---|---|
Name | Der Name den der Nutzer zur Anmeldung verwenden muss. Pro Nutzerdatenbank darf ein Name nur einmal vergeben werden. Gross/Kleinschreibung wird unterschieden. |
Passwort | Das Passwort das der Nutzer zu Anmeldung verwenden muss. Gross/Kleinschreibung wird unterschieden. |
Die Email des Nutzers. Immer gut zu wissen, falls Probleme auftreten. Wird von baseportal verwendet um einem Nutzer, der sein Passwort vergessen hat, dieses automatisch an seine EMail-Adresse zu schicken. Da das sehr häufig vorkommt ist dies eine grosse Arbeitserleichertung für den Administrator. | |
Rollen | Bestimmt die Rollen (Gruppen) eines Nutzers. Es können mehrere, durch Kommas getrennt (ohne zusätzliche Leerzeichen) angegeben werden; diese werden der Reihe nach geholt und zusammengeführt gewertet. Auch die normalen Rechte eines Nutzers können zusätzlich angegeben werden. |
Lesen, Schreiben, Ändern, Löschen | Diese 4 Felder bestimmen die Rechte für eine Datenbank. Dies kann für einzelne Felder bestimmt werden, die Namen der Felder müssen dann hintereinander weg durch Komma getrennt (ohne zusätzliche Leerzeichen) im entspechenden Rechte-Feld stehen. Undefinierte Felder werden einfach ignoriert. Ein Stern (*) bedeutet die Rechtefreigabe für alle Felder der betreffenden Datenbank. |
Gesperrt | Ist dieses Feld markiert, ist der Nutzer gesperrt und kann sich nicht anmelden. |
Erstellt am | Datum an dem der Nutzer eingetragen wurde. |
Natürlich ist auch eine Nutzerdatenbank eine ganz normale baseportal-Datenbank. Das bedeutet, sie können deren Aufbau völlig frei selbst bestimmen und beliebige eigene Felder hinzufügen oder nicht benötigte Felder löschen. Es werden einfach die angegebenen Feldnamen vom Anmelde-Modul verwendet und nur wenn diese vorhanden sind, wird deren Funktion ausgeführt.
Als zusätzliche Felder bieten sich ein "Kommentar"-Feld oder ein "Geburtstag"-Feld an. Sie können auch eine komplette Adress- und Kundenverwaltung darauf aufbauen!
|
Da eine Nutzer-Datenbank selbst eine normale baseportal-Datenbank ist, können Sie den Zugriff darauf wieder mit einer eigenen Nutzer-Datenbank regeln. Dadurch können Sie verschiedene Zugriffslevel definieren:
|
Der Eigner des baseportal-Zugangs hat dabei immer alle Rechte (vielleicht vergleichbar mit dem Nutzer "root" bei UNIX-Systemen). Die Nutzer-Datenbank einer Nutzer-Datenbank bestimmt die "Administratoren": Sie können neue Nutzer einragen, deren Rechte festlegen und diese auch wieder löschen. Die "Nutzer" können mit diesen Rechten auf die Datenbank zugreifen.
Ach ja, und die Nutzer-Datenbank einer Nutzer-Datenbank kann selbst natürlich wiederum auch eine Nutzer-Datenbank haben und... ;-)
|
Wird der Zugriff auf eine Datenbank über eine Nutzer-Datenbank geregelt, so gibt das <do action=all...> automatisch einen "Anmelden"-Button aus:
Keine Einträge vorhanden. |
Die restliche Ausgabe hängt von den Rechten ab, die unangemeldete Nutzer (ALLE) haben, in dieser Beispielausgabe nur Leserechte und sonst keine.
Kann man als unangemeldeter Nutzer garnicht auf die Datenbank zugreifen, so erscheint gleich das Anmeldeformular:
Wie üblich können Sie die Anmeldung durch einen Parameter beeinflussen:
Durch den neuen Parameter login beim "do action=all" kann die Art der Anmeldung für einen Nutzer gesteuert werden:
Wert | Bedeutung |
---|---|
yes | Ein entsprechender Anmeldungs-Link wird ausgegeben - auch wenn gar keine Nutzer-Datenbank existiert (Der Nutzen ist allerdings eher zweifelhaft). |
no | Keine (sichtbare) Anmeldung. Eine Anmeldung z.B. über eine eigene Anmeldeseite oder per URL-Angaben ist aber trotzdem möglich. |
closed | Keine Anmeldung möglich, egal wie. Dies kann z.B. für Testzwecke nützlich sein, um zeitweise jegliche Anmeldung auszuschliessen. |
lostpw | Bei falscher Anmeldung kann der Nutzer das Passwort auf Wunsch an die verzeichnete EMail-Adresse schicken lassen. |
top | Die Anmeldung wird ohne Link sofort über der restlichen Ausgabe platziert. |
bottom | Die Anmeldung wird ohne Link sofort unter der restlichen Ausgabe platziert. |
|
Beispiel:
<do action=all login=top,lostpw> |
Die Anmeldung wird sofort über der Ausgabe platziert. Hat ein Nutzer sein Passwort vergessen und meldet sich falsch an, so kann er sich das Passwort an die in der Nutzer-Datenbank verzeichnete EMail-Adresse schicken lassen. Da dies häufiger geschieht, als man glauben mag, ist dies eine grosse Erleichterung für den/die Seiten-Betreiber.
Sie können diese Anfrage zum Zusenden des Passworts auch direkt als Link auf Ihre Seite einbauen, dieser sähe dann ungefähr so aus:
<a href="http://...?htx=/name/seite&cmd=lostpw">Passwort vergessen?</a> |
Durch den Parameter login_users können nur bestimmte Nutzer zur Anmeldung in einem Template erlaubt werden:
<do action=all login_users=KONTROLLEUR,fongi,gabi> |
Hier werden nur die Nutzer KONTROLLEUR (in diesem Fall eine Rolle), fongi und gabi zur Anmeldung zugelassen.
Durch ein Minuszeichens - zu Beginn der Nutzerliste, werden die angegebenen Nutzer/Rollen ausgeschlossen. Alle anderen sind zugelassen:
<do action=all login_users=-ALLE,berger> |
Schliesst unangemeldete Nutzer (ALLE) und den Nutzer berger vom Zugriff aus.
|
Sie sind nicht auf die Standard-Anmeldung von <do action=all> angewiesen. Sie können die Anmeldung an anderer Stelle der Seite platzieren oder selbst eine Anmeldeseite erstellen und diese URL den Bearbeitern ihrer Datenbank zur Verfügung stellen. Wenn Sie "do action=all" verwenden und dort den Parameter login=no hinzufügen, so erscheint die normale Seitenausgabe ohne "Anmelden"-Button.
Um eine Anmeldung bei baseportal vorzunehmen müssen die Parameter "uid" für den Nutzer-Namen und "upw" für das Passwort übermittelt werden. Wenn Sie wollen, können Sie auch gleich eine URL mit diesen Parametern erstellen, z.B. so:
http://baseportal.de/cgi-bin/baseportal.pl?htx=/meinname/meineseite&uid=name&upw=passwort |
Natürlich ist dies nicht für jeden Fall das Bequemste. Um ein Anmeldeformular in einem Template zu integrieren, können Sie die neue "action"-Angabe login_form verwenden:
<do action=login_form> |
Gibt an dieser Stelle ein Anmeldeformular aus.
Um eine Anmeldung direkt von Ihrer Homepage aus zu ermöglichen benötigen Sie ein eigenes Anmelde-Formular:
Bitte melden Sie sich an:<p> <form action="http://baseportal.de/cgi-bin/bbeta.pl?htx=/meinname/ausgabeseite" method="post" enctype="multipart/form-data"> <input type=hidden name="htx=" value="/meinname/ausgabeseite"> <table> <tr><td>Name:</td><td><input type=text name="uid="></td></tr> <tr><td>Passwort:</td><td><input type=password name="upw="></td></tr> </table> </form> |
Das wars auch schon. Bauen Sie diesen Code in Ihre eigene Seite ein und rufen Sie sie dann auf. Das rot markierte "/meinname/ausgabeseite" müssen Sie dabei natürlich auf Ihre eigenen Werte ändern.
Vielleicht wollen Sie einen Service zur Verfügung stellen, der jedem erlaubt sich bei Ihnen zu registrieren, ohne dass Sie ihn extra eintragen müssen - so wie bei baseportal ja auch. Zur Umsetzung braucht es ein wenig Programmierung - richten Sie wie üblich eine Nutzer-Datenbank ein und erstellen Sie ein kleines Template mit dem gleich Namen (hier z.B. "nutzer.users") wie die Nutzer-Datenbank:
<perl> if(%_put) { if($_put{Name} eq "" || $_put{Passwort} eq "") { out "<b>Sie haben keinen Namen und/oder kein Passwort eingegeben.</b>"; } elsif(index($_put{EMail},'@')<0 || index($_put{EMail},'.')<0) { out "<b>Ihre EMail-Adresse enthält kein At-Zeichen ( @ ) und/oder keinen Punkt ( . ).</b>"; } else { get "Name==!$_put{Name}", "nutzer.users"; if($Name eq $_put{Name}) { out "<b>Ein Nutzer mit diesem Namen existiert bereits.</b>"; } else { $_put{Lesen}=$_put{Schreiben}="*"; $_put{"Ändern"}=$_put{"Löschen"}=""; # zur sicherheit falls manipulierte daten gesendet wurden put; out '<b>Sie sind jetzt registriert.</b><p>Hier gehts zur <a href="bbeta.pl?htx=/name/seite">Anmeldung</a>'; } } } unless($_put{Lesen}) { out <<EOF; <p>Registrieren Sie sich:<p> <form action="bbeta.pl?htx=$htx" method="post" enctype="multipart/form-data"> <input type=hidden name="htx=" value="$htx"> <table> <tr><td align=right>Name:</td><td><input type="text" name="Name:=" value="$_put{Name}"></td></tr> <tr><td align=right>Passwort:</td><td><input type="password" name="Passwort:="></td></tr> <tr><td align=right>EMail:</td><td><input type="text" name="EMail:=" size=30 value="$_put{EMail}"></td></tr> <tr><td></td><td><input type=submit value="Abschicken"> <input type=reset value="Zurücksetzen"></td></tr> </table> </form> EOF } </perl> |
Zuerst prüfen wir, ob das Formular bereits mit Daten abgeschickt wurde: Nur dann ist %_put gefüllt. Wenn ja, testen wir die Eingaben auf Korrektheit: Wurde ein Name und ein Passwort eingegeben? Sieht die EMail-Adresse wenigstens einigermassen richtig aus? Und, wichtig: Gibt es vielleicht schon einen Nutzer mit genau diesem Namen? Nur wenn alles stimmt, setzen wir die Rechte für Lesen und Schreiben für alle Felder und tragen den Nutzer in die Nutzer-Datenbank ein. Über einen Link gelangt er dann zur eigentlichen Datenbank (hier über das Template "/name/seite").
Da nicht jeder automatisch die Rechte für Ändern und Löschen erhalten soll, löschen wir diese explizit. Dies deshalb, da wir uns nicht 100% darauf verlassen können, dass jemand auch tatsächlich unser Registrierungsformular benutzt - er könnte genauso gut ein eigenes Formular erstellen und darin die Rechte für Ändern und Löschen als gesetzt mitschicken.
Die von uns gesetzten Rechte in $_put{Lesen} nutzen wir, um bei der Ausgabe des Formulars zu testen, ob wirklich eine Registrierung stattgefunden hat oder ein Eingabefehler ausgetreten ist.
Manchmal möchten Sie in einem Template eine Datenbank mit anderen Rechten aufrufen, als diese eigentlich hat. Sie können dies durch die Angabe der neuen Rechte-Parameter einfach bewerkstelligen:
Parameter | Beschreibung |
---|---|
rights_get | Rechte für Lesen |
rights_put | Rechte für Schreiben |
rights_mod | Rechte für Ändern |
rights_del | Rechte für Löschen |
Die Angaben sind dabei dieselben wie in einer Nutzer-Datenbank, also Feldnamen durch Komma , getrennt. Der Stern * bedeutet "Alle Rechte". Ein - steht für "Keine Rechte".
|
<do action=all rights_get=* rights_put=Name,Strasse,Ort> |
Gibt alle Felder der entsprechenden Datenbank aus und erlaubt das Hinzufügen der Felder Name, Strasse und Ort, unabhängig davon, wie diese Rechte in der Datenbank-Verwaltung gesetzt sind. Die Rechte zum Ändern und Löschen bleiben dabei unberüht - wollen sie diese definitiv löschen, müssen Sie ein rights_mod=- und ein rights_del=- dazufügen.
Nach jedem Datenbank-Befehl (init, get, put, mod und del) stehen die Rechte der Datenbank im Hash %datenbankname zur Verfügung. Erfolgte eine Anmeldung enthält $_user den Nutzernamen und der Hash %_user weitere Nutzerdaten:
init "adressen"; out <<EOF; Die Rechte der Datenbank "adressen":<p> Lesen: $adressen{_rights_get}<br> Schreiben: $adressen{_rights_put}<br> Ändern: $adressen{_rights_mod}<br> Löschen: $adressen{_rights_del}<p> Nutzer: $_user<br> EMail: $_user{email}<br> Passwort: $_user{password}<br> Session-Id: $_user{sid}<br> Rollen: $_user{roles}<br> Gesperrt: $_user{locked}<br> Nutzer-Datenbank: $_user{udb} EOF |
Gibt die Rechte der Datenbank adressen und den Namen, die EMail, das Passwort, die aktuelle Session-Id, die Rollen und eine mögliche Sperre eines eventuell angemeldeten Nutzers aus, sowie die zugehörige Nutzer-Datenbank.
Im folgenden wollen wir anhand eines möglichen Redaktionssystems eine komplexe Rechtevergabe demonstrieren. Zur Umsetzung ist dabei keine einzige Zeile Programmierung nötig! Folgende Personenkreise (Rollen) wollen wir dabei ermöglichen:
Rolle | Beschreibung |
---|---|
ALLE | Aussenstehende Nutzer. Sie sollen unangemeldet nur die für sie bestimmten Nachrichten lesen können. |
MITARBEITER | Angemeldete Nutzer. Sie können zusätzlich für den internen Gebrauch bestimmte Nachrichten lesen. |
REDAKTEUR | Redakteure schreiben die Nachrichten. |
MODERATOR | Nachrichten sind erst für normale Nutzer sichtbar, wenn Moderatoren diese freigegeben haben. |
ADMINISTRATOR | Administratoren bestimmen die Redakteure und Moderatoren. |
Wir benötigen dafür drei Datenbanken: Die eigentliche Nachrichten-Datenbank, eine Nutzer-Datenbank, die die Mitarbeiter, Redakteure und Moderatoren bestimmt, sowie eine Nutzer-Datenbank für die Nutzer-Datenbank, in der die Administratoren verzeichnet sind.
Hier die Nachrichten-Datenbank mit zwei Beispiel-Einträgen:
Das Feld Zuordnung gibt an, ob diese Nachricht jeder lesen darf, oder nur angemeldete Mitarbeiter - in beiden Fällen jedoch erst, nachdem Freigabe markiert ist. Im Kommentar können Redakteure Mitteilungen an die Moderatoren hinterlassen, dieses Feld ist nach aussen nicht sichtbar.
Und so sieht die zugehörige Nutzer-Datenbank mit einigen Beispieleinträgen aus:
ALLE, also alle unangemeldeten Nutzer erhalten lediglich Lesezugriff auf die Felder Titel und Text. Hans und bert sind REDAKTEURE: Sie dürfen nur Schreiben, natürlich ohne das Feld Freigabe, denn dies darf ja nur ein MODERATOR setzen: In diesem Fall der Nutzer gretel, der alles lesen und Freigabe ändern darf - sonst nichts. jan hat zusätzlich das Recht bekommen, Einträge zu löschen. ursl schliesslich ist eine einfache MITARBEITERIN.
Das (gleichnamige) Template "nachrichten", das die Nachrichten für alle ausgibt, ist denkbar einfach:
<html><head><title>Nachrichten</title></head> <body bgcolor=ffffff> <h2>Nachrichten</h2> <loop Freigabe==1 Zuordnung=="Für alle" sort=- range=0,10> <h3>$Titel</h3> $Text </loop> </body></html> |
Wir holen alle freigegebenen Nachrichten, die "für alle" bestimmt sind, und geben die neuesten 10 in einem loop aus.
|
Das Template für die Mitarbeiter ist ähnlich wie das Template für alle:
<html><head><title>Nachrichten</title></head> <body bgcolor=ffffff> <h2>Nachrichten</h2> <do action=login login=top> <loop db=nachrichten login_users=-ALLE Freigabe==1 sort=- range=0,10> <h3>$Titel</h3> $Text </loop> </body></html> |
Das Tag <do action=login login=top> erledigt alles zur Anmeldung nötige und gibt ein Anmeldeformular oder einen "Abmelden"-Link aus. Im loop müssen wir, da hier das Template (zwangsläufig) anders als die Datenbank heisst, diese speziell angeben. Mit login_users=-ALLE verhindern wir, dass auch unangemeldete Nutzer alle (auch die intern bestimmten) Nachrichten lesen können.
Ein einziges, sehr einfaches Templates erfüllt alle nötigen Funktionen für die Redakteure und Moderatoren:
<html><head><title>Nachrichten (Bearbeitung)</title></head> <body bgcolor=ffffff> <h2>Nachrichten (Bearbeitung)</h2> <do action=all db=nachrichten login_users=-ALLE,MITARBEITER> </body></html> |
Der Parameter login_users bestimmt, dass unangemeldete Nutzer (ALLE) und MITARBEITER keinen unbeschränkten Lesezugriff auf alle (also auch auf nicht freigegebene) Einträge der Datenbank bekommen.
Zu guter Letzt fehlt nur noch die Administratoren-Datenbank:
Dies ist die (einfache) Nutzer-Datenbank der Nutzer-Datenbank. Die Administratoren "fritsch" und "vertreter" können beliebige Redakteure, Moderatoren und Mitarbeiter mit beliebigen Rechten eintragen.
Und das entsprechende Template sieht so aus:
<html><head><title>Nachrichten / Nutzer (Administration)</title></head> <body bgcolor=ffffff> <h2>Nachrichten / Nutzer (Administration)</h2> <do action=all db=nutzer.users> </body></html> |
>> Natürlich befindet sich in der Bibliothek das komplette Redaktionssystem-Beispiel
Wenn Sie nicht auf <do action=all> zurückgreifen wollen, sondern Ihre eigene Anwendung programmieren, müssen Sie einige Sachen selbst übernehmen. Aber es ist ganz einfach. Hier der Rahmen einer solchen Anwendung:
<perl> do_login; if($_user eq "") { # nicht angemeldet do_login_form; # anmeldeformular ausgeben } else { # angemeldet out "<a href="/cgi-bin/$_myname?htx=...&cmd=do_login&uid=$uid&sid=$sid">Abmelden</a>"; } </perl> |
Das "do_login" übernimmt die Überprüfung der Anmeldung. War die Anmeldung erfolgreich ist $_user mit dem Nutzernamen gefüllt. Wenn Sie Links zusammensetzen, denken Sie daran, den Nutzernamen (in uid) und die Session-Id (in sid) mit zu übergeben, sonst verliert der Nutzer seine Anmeldung. Wird do_login mit dem Parameter "cmd=do_login" UND einem Nutzernamen (in uid) aufgerufen, so wird die Session abgemeldet.
Auch in Formularen muss der Nutzernamen und die Session-Id übermittelt werden; hier ein entsprechender Code-Abschnitt:
out '<input type=hidden name="uid=" value="'.$uid.'"><input type=hidden name="upw=" value="'.$upw.'">' if $_user ne ""; |
Zugriff auf Dateien und Verzeichnisse | Nach oben |
baseportal bietet nun auch die Möglichkeit, über Perl-Befehle Dateien (Templates) zu lesen, zu beschreiben, zu ändern, umzubenennen oder zu kopieren. Auch Verzeichnisse können erzeugt oder ausgelesen werden.
Zusammen mit Datenbanken gibt es 4 Datei-Typen in baseportal:
Form | Typ |
---|---|
name | Datenbank |
name.fields | Feld-Definition einer Datenbank |
name.htx | Seite |
name/ | Verzeichnis |
Die Grundbefehle heissen genauso wie beim Zugriff auf Datenbanken:
Befehl | Datenbank | Datenbank-Felder | Datei | Verzeichnis |
---|---|---|---|---|
get | get "Id==3", "datenbank"; | get "_field=Name", "db.fields"; | $inhalt=get "seite.htx"; | @dateien=get "dir/"; |
put | put [...], "datenbank"; | put ["_field", "Name"], "db.fields"; | put $inhalt, "seite.htx"; | put "dir_neu/"; |
mod | mod "Id==3", [...], "datenbank"; | mod "_field=Name", ..., "db.fields"; | mod $inhalt_neu, "seite.htx"; | |
del | del "Id==3", "datenbank"; | del "Feldname==!Name", "db.fields"; | del "seite.htx"; | del "dir/"; |
Pfade können, wie bei Datenbanken auch, relativ (dir/seite.htx) oder absolut (/meinname/dir/seite.htx) angegeben werden.
|
Im Moment kann nur auf Dateien mit der Endung: ".htx", also Seiten/Templates, zugegriffen werden. In Zukunft sollen aber weitere Dateitypen wie Bilder, Archive etc. dazukommen. Natürlich kann man ".htx"-Dateien auch als normale Textdateien verwenden und somit beliebige Daten darin speichern.
|
$inhalt=get "seite.htx"; |
Liest den kompletten Inhalt der Datei seite in die Variable $inhalt ein. Die einzelnen Zeilen sind durch den Zeilentrenner \n getrennt.
Eine Datei kann auch zeilenweise gelesen werden:
@inhalt=get "seite.htx"; |
Liest den Inhalt der Seite seite in das Array @inhalt ein. Jedes Element des Arrays enthält nun eine Zeile, $inhalt[0] also die erste, $inhalt[1] die zweite usw. Die Zeilentrenner sind jeweils entfernt.
@inhalt=get "seite.htx", "_raw"; |
Belässt die Zeilentrenner \n am Ende jeder Zeile.
put $zusatz, "seite.htx"; |
Fügt zur Seite seite den Inhalt der Variablen $zusatz hinzu.
Es können auch mehrere Zeilen auf einmal hinzugefügt werden, entweder durch eigenhändiges Hinzufügen des Zeilentrenners...
put "Erste Zeile\nZweite Zeile\nDritte Zeile", "seite.htx"; |
...oder durch Übergabe der einzelnen Zeilen...
put ["Erste Zeile", "Zweite Zeile", "Dritte Zeile"], "seite.htx"; |
...oder durch Übergabe eines Array-Verweises:
put \@zusatz, "seite.htx"; |
Jedes Element des Arrays @zusatz entspricht einer Zeile.
put ["Eins", "Zwei", "Drei"], "seite.htx", "_raw"; |
Unterlässt das automatische Hinzufügen der Zeilentrenner, so dass tatsächlich "EinsZweiDrei" geschrieben wird.
mod $inhalt_neu, "seite.htx"; |
Ändert den Inhalt der Seite seite in den Inhalt der Variablen $inhalt_neu. Der alte Inhalt der Seite seite geht verloren.
Ebenso wie beim put können mehrere Zeilen durch einen Array-Verweis übergeben werden und auch hier funktioniert das _raw:
mod \@inhalt_neu, "seite.htx", "_raw"; |
Die Zeilen des Arrays @inhalt_neu ersetzen den ursprünglichen Inhalt der Seite seite. Zeilentrenner werden dabei nicht automatisch hinzugefügt.
Oft wird der Inhalt einer Datei gelesen, verändert und dann wieder zurückgeschrieben. Was auf den ersten Blick oder bei einem lokalen Einzelplatzrechner funktioniert, wird bei Web-Anwendungen früher oder später zu Problemen führen, da mehrere Nutzer gleichzeitig auf die Daten zugreifen können.
baseportal erlaubt zur Lösung dieses Problems, dem Befehl mod einen Perl-Code zu übergeben, der mit dem Inhalt der Datei ausgeführt wird. Das Ergebnis des Codes wird in die Datei geschrieben. Es wird dabei sichergestellt, dass während des gesamten Vorgangs kein anderer auf die Datei zugreift. Der Inhalt der Datei wird in $_ bereitgestellt - der Rückgabewert des Codes wird zum neuen Inhalt.
mod { ++$_ } "zaehler.htx"; |
Liest den Inhalt der Seite zaehler ein, erhöht ihn um 1 und schreibt den neuen Wert zurück. Dieser Code ist "thread-safe".
Durch Anfügen des Parameters _line wird der Code zeilenweise durchlaufen:
mod { $cnt++; "$cnt. $_" } "zeilen.htx", "_line"; |
Numeriert die Zeilen der Seite zeilen durch. Bevor nicht die komplette Datei durchgearbeitet wurde kann niemand auf sie zugreifen.
|
del "seite.htx"; |
Löscht die Seite seite.
Definition:
Ergebnisliste=get Verzeichnis[, Mode, [-]Filter, Entfernen, Ergebnishash]; |
Name | Typ |
---|---|
aaa/ | Verzeichnis |
bbb/ | Verzeichnis |
ccc/ | Verzeichnis |
aaa.htx | Seite |
bbb | Datenbank |
bbb/ddd | Datenbank in Verzeichnis "bbb/" |
ccc.htx | Seite |
Name | Bedeutung |
---|---|
_down | Verzeichnis wird rekursiv, d.h. mit allen Unterverzeichnissen (und deren Unterverzeichnissen etc.), durchlaufen |
_base | Der Grundpfad des Verzeichnisses wird allen Einträgen vorangestellt (=absolut) |
_name | Es wird nur der Name des Eintrags, ohne den jeweiligen Pfad, aufgenommen |
_join | Sortiert Verzeichnisse und Dateien zusammen |
_dir | (Nur) Verzeichnisse werden in die Ergebnisliste aufgenommen |
_file | (Nur) Dateien (Datenbanken und Seiten) werden in die Ergebnisliste aufgenommen |
_db | (Nur) Datenbanken werden in die Ergebnisliste aufgenommen |
_htx | (Nur) Seiten werden in die Ergebnisliste aufgenommen |
Mehrere Werte können durch Komma , und/oder Leerzeichen getrennt angegeben werden, z.B.: "_down, _base, _db, _htx". Ausserdem kann ab dem zweiten Wert der Unterstrich weggelassen werden, so dass z.B. "_down,base,db,htx" dasselbe bedeutet.
|
Beispiele:
@dateien=get "dir/"; |
Holt alle Verzeichnisse, Datenbanken und Seiten im Verzeichnis dir.
@dateien=get "dir/", "_file"; |
Holt alle Dateien (Datenbanken und Seiten) im Verzeichnis dir.
@dirs=get "dir/", "_down,dir"; |
Holt alle Verzeichnisse und Unterverzeichnisse im Verzeichnis dir.
@dbs=get "dir/", "_down,dir,db,join"; |
Holt alle Verzeichnisse und Datenbanken im Verzeichnis dir und allen Unterverzeichnissen und sortiert diese miteinander, so dass die Datenbanken in Unterverzeichnissen gleich nach diesen aufgelistet werden.
@backups=get "dir/", "_down,db", qr/(^|\/)backup_/i; |
Holt alle Datenbanken im Verzeichnis dir und allen Unterverzeichnissen, deren Name mit "backup_" (gross oder klein - wg. des angehängten "i") anfängt.
@seiten=get "dir/", "_down,base,htx", qr/-\d+\.htx/, qr/\.htx$/; |
Holt alle Seiten im Verzeichnis dir und allen Unterverzeichnissen, die nicht mit einer Zahl enden (z.B. "text123.htx" wird nicht geholt). Allen anderen Seiten wird der Basispfad vorangestellt und das ".htx" am Ende abgeschnitten.
put "dir_neu/"; |
Legt das Verzeichnis dir_neu an. Ein gleichnamiges Verzeichnis darf nicht existieren.
del "dir/"; |
Löscht das Verzeichnis dir, allerdings nur, wenn es komplett leer ist, also wenn keine Dateien oder Verzeichnisse darin enthalten sind.
Um ein volles Verzeichnis zu löschen, muss man ein "_force" anhängen:
del "dir/", "_force"; |
Löscht das Verzeichnis dir, egal ob es leer ist oder nicht. Entsprechend vorsichtig sollte man mit diesem Parameter umgehen - durch einen einzigen Befehl können Dutzende Datenbanken und Dateien auf einmal gelöscht werden!
Neues beim Zugriff auf Datenbanken | Nach oben |
del ist wie get
--> gelöschte Einträge stehen danach in ...}[..] oder können mit get_next durchlaufen werden
mod ist wie del und put
mod "Id==3", sub { ... }, "db";
Dateiverwaltung | Nach oben |
Definition:
move von, nach[, Mode]; |
Sowohl von als auch nach können Datenbanken, Dateien oder Verzeichnisse sein - mit jeweils anderen Auswirkungen.
von kann einen Stern * enthalten, der für beliebige Zeichen steht: test* holt somit alle Dateien die mit test beginnen oder dir/* alle Dateien oder Verzeichnisse im Verzeichnis dir. Eine noch genauere Auswahl ist mit regulären Ausdrücken möglich.
Es können auch Listen übergeben werden, so dass mehrere Dateien oder Verzeichnisse auf einmal verschoben werden.
Die Werte von Mode sind ähnlich wie bei "Verzeichnis lesen":
Name | Bedeutung |
---|---|
_force | Ziel wird überschrieben, falls es bereits existiert |
_down | Verzeichnisse werden rekursiv, d.h. mit allen Unterverzeichnissen (und deren Unterverzeichnissen etc.), durchlaufen |
_dir | (Nur) Verzeichnisse werden verschoben |
_file | (Nur) Dateien (Datenbanken und Seiten) werden verschoben |
_db | (Nur) Datenbanken werden verschoben |
_htx | (Nur) Seiten werden verschoben |
Beispiele:
move "alt.htx", "neu.htx"; |
Benennt die Seite alt in die Seite neu um. Es darf keine Seite mit dem Namen neu bereits existieren.
move "alt.htx", "neu.htx", "_force"; |
Benennt die Seite alt in die Seite neu um, auch wenn die Seite neu bereits existiert. Achtung: Der Inhalt der Seite neu ist damit verloren!
move "/meinname/test", "dir/"; |
Verschiebt die Datenbank /meinname/test in das Verzeichnis dir. In diesem Verzeichnis darf keine Datenbank mit diesem Namen existieren.
move "dir1/", "dir2/", "_force"; |
Verschiebt das Verzeichnis dir1 mit allen Dateien und Unterverzeichnissen in das Verzeichnis dir2. Wenn in dir2 bereits ein Verzeichnis namens dir1 existiert, wird dieses vorher gelöscht. Achtung: Alle im überschriebenen Verzeichnis dir1 enthaltenen Dateien und Unterverzeichnisse gehen komplett verloren!
move "dir1/*"; |
Verschiebt alle Dateien (Datenbanken und Seiten) von dir1 in das aktuelle Verzeichnis; existieren im aktuellen Verzeichnis bereits gleichnamige Dateien, so werden diese übersprungen.
move "*", "dir1/", "_down"; |
Verschiebt alle Dateien und Unterverzeichnisse vom aktuellen Verzeichnis in das Verzeichnis dir1; gleichnamige Dateien oder Verzeichnisse werden übersprungen.
move "dir1/test*", "../dir2/", "_file,force"; |
Verschiebt alle Dateien (Datenbanken und Seiten) von dir1 die mit "test" beginnen in das darüberliegende Verzeichnis dir2; gleichnamige Dateien oder Verzeichnisse in ../dir2 werden überschrieben.
move qr#dir1/test[123](_bck)?#, "", "_htx,force"; |
Verschiebt die Seiten test1, test2, test3, test1_bck, test2_bck oder test3_bck (wenn es sie gibt) in das aktuelle Verzeichnis. Gleichnamige Dateien werden überschrieben.
Definition:
copy von, nach[, Mode]; |
Kopieren ist tatsächlich genau dasselbe wie Verschieben, nur dass die ursprüngliche Datei dabei bestehen bleibt. Eine Erklärung erübrigt sich deshalb - Sie können genau dieselben Beispiele wie oben mit "copy" statt "move" verwenden.
Jede Datenbank, jede Datei und jedes Verzeichnis hat Eigenschaften, die nicht zum Inhalt selbst gehören, sondern Informationen über die Datei an sich geben. Dazu gehören z.B. die Grösse einer Datei, wann sie erzeugt wurde oder welche Rechte sie hat.
Darüber hinaus möchte man oft zusätzliche, selbst definierte Informationen zu einer Datei oder einem Verzeichnis speichern, beispielsweise den Autor, ein Ablaufdatum, in welcher Sprache der Text ist etc.
baseportal unterstützt das Speichern und Auslesen dieser auch Meta-Informationen genannten Werte direkt.
Hier alle vordefinierten Eigenschaften:
Name | Bedeutung |
---|---|
_type | Dateityp: dir = Verzeichnis, db=Datenbank, htx=Seite, zip=Archiv |
_rights | Rechte der Datei |
_accessed | Zeitpunkt des letzten Zugriffs auf die Datei (nicht bei allen Betriebssystemen verfügbar) |
_modified | Zeitpunkt der letzten Aenderung an der Datei |
_created | Zeitpunkt der Erstellung der Datei |
_amount_all | Anzahl der Einträge in einer Datenbank |
_size | Grösse der Datei in Bytes |
_exists | Datei existiert |
_props | Alle Eigenschaften auf einmal |
Es können entweder einzelne Eigenschaften gelesen werden...
Ergebnis=get Werte, Datei; |
...oder alle auf einmal:
get "_props", Datei, Ergebnishash; |
Beispiele:
out "Verzeichnis dir1 existiert" if get "_exists", "dir1/"; |
Testet ob das Verzeichnis dir1 existiert. Dies kann auch mit _size überprüft werden:
$groesse=get "_size", "kunden"; if(not defined $groesse) { out "Datenbank kunden existiert nicht"; } elsif($groesse==0) { out "Datenbank kunden ist leer"; } else { out "Datenbank kunden ist $groesse Bytes gross"; } |
Gibt die Grösse der Datenbank kunden in Bytes aus, wenn Sie existiert.
($Autor, $Rechte, $Erstellung, $Groesse)=get "Autor,_rights,created,size", "seite.htx"; |
Holt den Autor, die Rechte, den Zeitpunkt der Erstellung und die Grösse der Datei. Autor ist dabei eine selbstdefinierte Eigenschaft.
|
Es können auch alle gespeicherten Eigenschaften auf einmal geholt werden:
get "_props", "tests/"; |
speichert alle Eigenschaften vom Verzeichnis tests im Hash %_props. Mit z.B.
$_props{_size} |
kann nun auf die einzelnen Eigenschaften zugegriffen werden.
|
Gibt man einen Ergebnishash an, werden die Eigenschaften darin gespeichert:
get "_props", "tests/", "tests_props"; |
speichert alle Eigenschaften vom Verzeichnis tests im Hash %tests_props. Die verschiedenen Eigenschaften sind dann so zu erreichen:
$tests_props{Eigenschaft} |
Die meisten der speziellen Eigenschaften, wie Erzeugungsdatum oder die Grösse, können nicht direkt verändert werden. ((rights z.b. schon - andere sachen auch? erzeugungsdatum doch? ))
put ["Name", "Wert", "Name2", "Wert2",...], <i>Datei</i>, "_props"; |
put "_props", ["Name", "Wert", "Name2", "Wert2",...], <i>Datei</i>; |
oder
put "_props", "Name:=Wert Name2:=Wert2...", <i>Datei</i>; |
Es kann nicht mehrere gleichnamige Eigenschaften geben; bestehende Eigenschaften werden mit neuen Werten einfach überschrieben. Deshalb braucht und gibt es keinen mod-Befehl zum Ändern von Eigenschaften.
Auch ein Löschen geht mit
put ["Name", ""], "datei", "_props";
also warum nich gleich 1 befehl?
del "Name,Name2", <i>Datei</i>, "props"; |
Komplexe Datenstrukturen speichern und ausgeben (Serialisierung) | Nach oben |
Das Aufbereiten komplexer Datenstrukturen wie Listen oder Hashes zur Speicherung in Datenbank-Feldern oder Dateien, nennt man Serialisierung. Die Listen oder Hashes können beliebig verschachtelt sein, so dass auch Listen von Listen oder Hashes von Listen von Hashes (oder ... ;-) ) möglich sind.
Die Funktion dafür heisst serial. Ein spezielles Gegenstück zu serial gibt und braucht es nicht, denn der serialisierte Inhalt ist nichts anderes als Perl-Code, der -mit eval ausgeführt- eine entsprechende Liste oder einen entsprechenden Hash erzeugt:
$ser=serial @liste; |
speichert die Liste @liste in serialisierter, komprimierter Form in der Variablen $ser.
@liste=eval $ser; |
erzeugt die in $ser gespeicherte Liste wieder. Nun macht obiger Code an sich wenig Sinn, da die Liste ja schon existiert. Interessant wird es, wenn man die serialisierte Form speichert:
put serial(%hash), "bla.htx"; |
speichert den Hash %hash in der Seite bla. Die Klammern braucht es, da "bla.htx" sonst dem Hash zugerechnet würde und nicht als Parameter für put.
%hash=eval get "bla.htx"; |
liest den gespeicherten Hash wieder ein.
Auch das Speichern in Datenbankfeldern geschieht denkbar einfach. Dabei weiss die Datenbank garnichts davon, dass in einem Feld z.B. eine Liste gespeichert ist; sie sieht nur den serialisierten Code. Folglich wird es zu Problemen oder unerwarteteten Ergebnissen kommen, wenn eine Serialisierung in bestimmte Feldtypen wie "Zahl" oder "EMail" geschrieben wird - diese überprüfen z.B. die Eingabe auf Korrektheit (Ist es eine Zahl? Ist es eine EMail-Adresse?), was mit der serialisierten Form nicht funktionieren kann. Auch eine Sortierung wird nicht klappen. Am Besten verwenden Sie für Felder, in denen Sie Listen oder Hashes speichern wollen die Feldtypen text oder textarea.
@kinder=("Barbara", "Ingrid", "Stefan"); put ["Name", "Hans", "Kinder", serial(@kinder)], "leute"; |
speichert die Liste @kinder im Feld Kinder in der Datenbank leute. Die Klammern beim serial sind in diesem konkreten Fall zwar nicht unbedingt zwingend, aber wenn dahinter weitere Felder kommen sollten, sind sie zur Abgrenzung nötig.
get "Name==!Hans", "leute"; @kinder=eval $Kinder; out "Kinder von $Name: @kinder"; |
gibt die Kinder von Hans aus.
|
Dasselbe wie mit Listen funktioniert genauso mit Hashes, hier gleich in einer verschachtelten Ausführung:
%cds= ( "lc1109" => { "Interpret" => "Underworld", "Titel" => "dubnobasswithmyheadman", "Preis" => 19.95 }, "lc0121" => { "Interpret" => "Phil Collins", "Titel" => "Face Value", "Preis" => 12.95 }, "lc0485" => { "Interpret" => "The Police", "Titel" => "Zenyatta Mondatta", "Preis" => 14.95 } ); put ["Name", "Concrete Record Store", "Sortiment", serial(%cds)], "plattenlaeden"; |
speichert den Hash %cds im Feld Sortiment in der Datenbank plattenlaeden.
Hier das Auslesen:
while(get "Name~=c", "plattenlaeden") { out "<b>Laden: $Name</b><br>"; %cds=eval $Sortiment; foreach $nr (sort keys %cds) { $cds=$Sortiment{$nr}; out "Nummer: $nr, Interpret: $cds{Interpret}, Titel: $cds{Titel}, $cds{Preis}<br>"; } out "<br>"; } |
liest alle Einträge der Datenbank plattenlaeden die mit c beginnen und gibt deren Name, sowieso alle CDs (Interpret, Titel und Preis) im Sortiment aus.
|
serial kann aber auch für die Ausgabe verschachtelter Listen oder Hashes verwendet werden, was für Debugging-Zwecke sehr hilfreich ist:
out serial @liste, "_html"; |
gibt die Liste @liste in formatierter Form aus: HTML-Tags werden mit convert_html "unscharf" gemacht und die Ausgabe wird von <pre>...</pre> umschlossen, so dass der Browser auch Verschachtelungen gut leserlich darstellt. Will man dies nicht, so muss man ein text anhängen:
out serial %hash, "_text"; |
gibt den Hash %hash in reinem (formatierten) Text aus.
Zugriff auf das Internet | Nach oben |
Sie können mit baseportal Seiten und sogar Datenbanken oder Verzeichnisse von anderen Internet-Servern laden und einbinden oder verarbeiten. Das Ganze geschieht dabei völlig transparent, d.h. die Befehle sind genau die gleichen wie beim Bearbeiten von lokalen Dateien; es muss lediglich eine URL (mit http:// zu Beginn) angegeben werden.
<include src=http://yahoo.de> |
lädt die Startseite von yahoo.de und bindet sie an dieser Stelle im Template ein.
$x=get "http://baseportal.de/agb.html"; |
liest die HTML-Seite mit den AGBs vom Server baseportal.de und speichert sie in der Variablen $x.
Mit copy können Sie eine HTML-Seite direkt in eine Datei speichern:
copy "http://www.spiegel.de", "spiegel.htx"; |
holt die Startseite von spiegel.de und speichert sie in der Datei spiegel.htx.
Ebenso einfach wie der Zugriff auf Internet-Seiten funktionieren alle baseportal-Befehle über das Internet. Auf der Gegenseite muss sich allerdings natürlich ebenfalls ein baseportal-Server befinden.
|
get "db=/baseportal/wishes", "http://baseportal.de"; |
liest die komplette Datenbank /baseportal/wishes vom Server baseportal.de. Sie kann danach ganz normal mit get_next durchlaufen und abgearbeitet werden.
Ist nur der Server angegeben, so nimmt baseportal an, dass das baseportal-Programm auf der gegenüberliegenden Seite in cgi-bin liegt und baseportal.pl heisst. Ist dem nicht so, so muss dies extra angegeben werden:
get "db=/baseportal/wishes", "http://baseportal.de/cgi-local/baseportal.pl"; |
Parameter können sowohl wie üblich als Befehlsparameter oder direkt in der URL mit angegeben werden:
get "db=/huber/db1 Name~=a range=0,10", "http://netpure.de"; |
holt aus der Datenbank /huber/db1 vom Server netpure.de die ersten 10 Einträge bei denen das Feld Name mit "a" beginnt. Diese Abfrage ist genau dasselbe wie:
get "http://netpure.de/cgi-bin/baseportal.pl?db=/huber/db1&Name~=a&range=0,10"; |
Der Befehl get hängt übrigens selbständig noch ein "&cmd=get" an die URL, so dass die Gegenseite weiss, welcher Befehl ausgeführt werden soll.
Ebenso einfach funktioniert das Schreiben in eine entfernte Datenbank:
put ["Name", "Heinz"], "http://netpure.de/cgi-bin/baseportal.pl?db=/huber/db1"; |
$x=get "http://netpure.de/cgi-bin/baseportal.pl?get=/baseportal/wishes.htx"; |
put "Irgend ein Text", "http://netpure.de/cgi-bin/baseportal.pl?put=/baseportal/wishes.htx"; |
- das jetzige "htx" muesste eigentlich "run" heissen
- "uid" -> "user"
- "upw" -> "pass"
- "sid" -> "session"
und dann noch alles mit unterstrich?
_run
_user
_pass
_session
_db
entsprechend heissen die variablen:
aktuelles htx (oder doch auch: _htx & d:/htdocs/baseportal/data ? waer auch ok...)
nutzer
Passwort
Session Id
/baseportal/rights/admins.users aktuelle db
@files=get "http://netpure.de/cgi-bin/baseportal.pl?get=/baseportal/wishes/", "down"; |
move "http://baseportal.de/cgi-bin/baseportal.pl?get=/baseportal/wishes", "http://baseportal.de/cgi-bin/baseportal.pl?put=/baseportal2/wishes"; |
move "http://baseportal.de?/baseportal/wishes", "http://baseportal.de?/baseportal2/wishes"; |
copy "http://baseportal.de/cgi-bin/baseportal.pl?get=/baseportal/wishes", "wishes"; |
Alle oben angegebenen Befehle funktionieren nur, wenn bei der Rechtevergabe der Datenbanken oder Seiten die entsprechenden Rechte (Lesen oder Schreiben oder...) für "andere baseportal-Nutzer" ("Andere baseportal-Nutzer dürfen entsprechend dieser Rechte auf die Datenbank zugreifen... blabla") vergeben sind. Wollen Sie auf eine auf eine nicht freigegebene Datenbank oder Seite zugreifen, müssen Sie einfach den Nutzernamen und das Passwort mitschicken:
Beispiele:
- baseportal schickt im header ("Content-type: baseportal/db") mit, was es is - obs nun ne datenbank ist oder n verzeichnis, ne liste, ne seite oder was auch immer........ header auslesen im "get_url"
Zugriff auf Datenbank-Felder | Nach oben |
Manche haben es schon immer vermutet: baseportal kennt intern eigentlich gar keine unterschiedlichen Feldtypen. Für baseportal ist im Grunde jeder Eintrag eine beliebig lange Folge von beliebigen Zeichen. Nach aussen wird die "Illusion" von Feldtypen durch Filter erzeugt. Diese sind in etwa mit den stored procedures bei SQL vergleichbar.
Zu jedem Datenbank-Befehl gibt es einen zugehörigen Filter
Filter | Bedeutung |
---|---|
_field | Feldname |
_sort | Sortierung (z.b. nach Zahl oder Text) |
_form | Ausgabe für Formular |
_put | Wird beim Schreiben eines Eintrags durchlaufen |
_get | Wird beim Lesen eines Eintrags durchlaufen |
_sel | Wird bei der Abfrage (z.B. "Name~=a") durchlaufen |
_del | Wird beim Löschen eines Eintrags durchlaufen |
_mod | Wird beim Ändern eines Eintrags durchlaufen |
_params | Beliebige Parameter, z.B. die Grösse eines Eingabefeldes oder die Nachkommastellen oder... |
put
|
get
|
mod
| |||||||||||
|
del
|
((das muesste eigentlich auch mit "get" gehen! --> get "nutzer.fields"; )
Nach einem init oder einem der Datenbank-Befehle get, put, mod oder del stehen im Hash %datenbankname Informationen über die Felder der Datenbank. Beispiel:
init "nutzer"; out $nutzer{_field}[0]; |
gibt den Namen des ersten Datenbankfeldes aus (immer "Id" ;-) ). Hier eine Schleife durch alle Felder der aktuellen Datenbank:
init; foreach $_field (@{$$_db{_field}}) { out "$_field<br>"; } |
PHP | Nach oben |
PHP ist nun nahtlos in baseportal integriert - PHP-Code wird innerhalb der Templates ausgeführt und dieser PHP-Code kann mit den von baseportal gewohnten Befehlen auf baseportal-Datenbanken zugreifen. Das Ergebnis der Abfragen steht wiederum direkt in PHP-Variablen zur Verfügung. Oder anders: Alles funktioniert so wie es soll ;-)
PHP-Code wird genauso in Seiten eingebaut wie Perl-Code, nur dass das zugehörige Tag php heisst:
<php> out("Ja, ich bin PHP-Code! ;-)"); </php> |
Der Befehl zur Ausgabe heisst auch hier out (nicht echo wie in PHP sonst). In PHP müssen alle Funktionen Klammern haben.
Danke an Sander für die schöne Vorlage ;-)
Wie gewohnt stehen die baseportal-Befehle zum Zugriff auf Datenbanken zur Verfügung. Bis auf kleinere Anpassungen auf PHP-Seite gibt es keine Unterschiede.
get("Id==*", "adressen"); out("$_amount Einträge."); while(get_next()) { out("$Name - $Strasse - $Ort<br>"); } |
Holt alle Einträge aus der Datenbank adressen, gibt die Anzahl und den Inhalt aus.
|
Um PHP-Code direkt in Perl ausführen zu können gibt es den Befehl php:
<perl> $x=11; $r=php 'out(...irgendwas php-spezifisches... '.$x.' ); return 5;'; out $r; </perl> |
((hier wär n praktisches beispiel ganz pfiffig, auch mit var-übergabe))
Gibt ... aus und den Wert 5 zurück. Dies wird in $r gespeichert und dann $r ausgegeben.
((was is mit komplexeren varstrukturen? arrays, hashes, arrays von arrays etc. --> sieht eigentlich nach nem serial f. perl & php jeweils aus......))
Das geht natürlich auch umgekehrt:
Um Perl-Code direkt in PHP ausführen zu können gibt es die Funktion perl:
<php> $r=perl "$_=$x; s/...irgendne ausgefuchste regex.../.../g; return $_;"; </php> |
Jetzt bloss nicht durcheinander kommen ;-)
Variablen stehen nicht automatisch in beiden Sprachen zur Verfügung:
<php> $x=3; </php> <perl> out $x; </perl> |
mhhhhhhhhhhh.... gibt aber n "problem":
<php> $x=3; </php> ...html-code... x= $x |
damit wäre php "anders" als perl........ mhhhhh...
eine möglichkeit wäre _jedesmal_ den kompletten variablenbaum durchzugehen und entsprechend beim anderen zu setzen - is aber schon ganz schön aufwändig!
oder:
<php> import("$x"); $x++; export("$x"); </php> |
XML | Nach oben |
XML (englisch eXtensible Markup Language) entstand aus der Tatsache, dass HTML, die "Sprache" des Web an seine Grenzen gestossen ist. HTML ist im Grunde nicht sonderlich kompliziert, was sicherlich ein Grund für seinen grossen Erfolg war. Es gibt einen feststehenden Satz an Tags (das was zwischen den < und >-Zeichen steht), die zumindest bei den ursprünglichen und wichtigsten wie <h1>, <b> oder <i> (fast) auf jedem Browser auch die gleiche Bedeutung haben und (mehr oder weniger) gleich dargestellt werden.
HTML hat viel geleistet, aber dessen Grenzen zeigten sich schon sehr früh in den Anfangstagen des Webs. Was, wenn bestimmte Textteile blinkend dargestellt werden sollten? Oder wenn man möchte, dass sie mit einem roten Rahmen versehen und -falls möglich- vorgelesen werden? Oder, dass sie von links nach rechts über den Bildschirm fliegen? Oder komplizierte Berechnungen damit durchgeführt werden sollen?
Nun gut, wenn der Bedarf da ist, warum sollte man HTML nicht einfach um zusätzliche Tags erweitern? Genau das wurde munter getan, angefangen vom vielgescholtenen <blink>...</blink>-Tag von Netscape über das <marquee>...</marquee> für Laufschrift von Microsoft hin zum <layer>-Tag, diesmal wieder von Netscape. Hinzu kamen Erweitungen zusätzlich zu HTML, wie Javascript um Programmierlogik auf Webseiten unterzubringen oder CSS für eine bessere Gestaltungskontrolle.
Recht schnell wurde klar: Es bedurfte einer Sprache, mit der man universell beliebige Tags definieren kann. Zwar existiert mit SGML schon länger eine solche universelle "Dokumentensprache" (von der auch HTML abgeleitet wurde), aber sie wurde für das Web als zu kompliziert betrachtet. Die Antwort auf diese Anforderung lautet: XML - und das wird definitiv der nächste grosse Trend - z.B. will Microsoft alle seine Software auf XML umstellen... Nun, baseportal kann es (mehr oder weniger) bereits JETZT... ;-)
>> Hier eine XML-Demoseite
Im folgenden wird erklärt, was da genau vorgeht und wie man so etwas selbst macht!
Mein Lieblingsbeispiel ist ein neues Tag für "Code-Bereich". In der Dokumentation oder im Forum bei baseportal kommt es ständig vor, dass Code-Teile angegeben werden müssen, also so etwas wie:
<h1>Meine Datenbank</h1> <do action=all> |
Wie bei diesem Beispiel (durch den grauen Hintergrund) möchte man diese Code-Teile herausstellen; es ist übersichtlicher und sieht besser aus. Hinzu kommt: Darin enthaltene HTML-Tags sollen NICHT ausgeführt, sondern inklusive der < und >-Zeichen dargestellt werden. Dazu ist die Umwandlung in < bzw. > nötig.
Der Quelltext des obigen HTML-Abschnitts sieht also auf der Seite so aus:
<table width=90% cellpadding=10><tr><td bgcolor=f0f0f0><font size=3><pre> <h1>Meine Datenbank</h1> <do action=all> </pre></td></tr></table><br> |
Ohne XML-Parser darf man all dies jedesmal per Hand machen!! Ein extrem mühsamer und fehleranfälliger Weg. Hinzu kommt: Entschliesst man sich irgendwann die Code-Darstellung zu ändern, z.B. einen Rahmen um den Hintergrund zu ziehen, so darf man dies an allen entsprechenden Stellen im Text erledigen. Und noch ein Vorteil: Durch mehrere unterschiedliche Definitionen für das neue "Code-Tag" lässt sich aus ein und derselben Quelldatei die Ausgabe für verschiedene Formate erzeugen, z.B. einmal für HTML, einmal für WAP, einmal als reiner Text.
So, jetzt zur Praxis:
Mit den neuen XML-Funktionen von baseportal ist es jetzt möglich folgendes zu schreiben:
<code> <h1>Meine Datenbank</h1> <do action=all> </code> |
und baseportal erzeugt automatisch den gewünschten Hintergrund und ersetzt die < und >-Zeichen.
Dabei ist der Name des neuen Tags "code" völlig frei gewählt, ebenso wie die Funktionalität, wie wir im folgenden sehen werden. Übrigens existiert ein Tag namens "code" bereits im HTML-Standard, es hat aber ausser einem anderen Zeichensatz ("Schreibmaschinenschrift", diesen Effekt kann man ebenso mit <tt>...</tt> erreichen) üblicherweise keine andere Wirkung. Hier sieht man eine weitere Eigenschaft der neuen Tags: Neuere Definitionen können ältere überlagern, auch bestehende HTML-Tags können neu definiert werden - wer mag, kann sogar die baseportal-internen Tags wie do, loop, include oder perl umschreiben. ;-)
Wie sieht nun die Definition der Funktionalität des neuen Tags aus? Oder anders: Was soll es machen?
Fangen wir mit dem grauen Hintergrund an. Die Definition ist ganz einfach.
<table width=90% cellpadding=10><tr><td bgcolor=f0f0f0><font size=3><pre>$_</pre></td></tr></table><br> |
Wichtig ist das $_: Stösst baseportal bei der Analyse eines Templates (dem sog. "Parsing") auf das Tag "code" setzt es den vom <code>...</code> umschliessenden Text an die Stelle der Definition an der das $_ steht. Dann setzt es das komplette Ergebnis an die Stelle des "code"-Tag im Template.
Hier der Ablauf im Detail:
1. baseportal "entdeckt" das Tag "code":
Ein Beispiel: <code> <h1>Meine Datenbank</h1> <do action=all> </code> Weiter mit normalen HTML... |
2. Der umschlossene Text wird $_ zugewiesen...
<h1>Meine Datenbank</h1> <do action=all> |
3. ...und an der Stelle von $_ in die Definition des "code"-Tags eingefügt:
<table width=90% cellpadding=10><tr><td bgcolor=f0f0f0><font size=3><pre> <h1>Meine Datenbank</h1> <do action=all> </pre></td></tr></table><br> |
4. Der ganze resultierende Text wird jetzt an der Stelle des Tags eingefügt:
Ein Beispiel: <table width=90% cellpadding=10><tr><td bgcolor=f0f0f0><font size=3><pre> <h1>Meine Datenbank</h1> <do action=all> </pre></td></tr></table><br> Weiter mit normalen HTML... |
5. baseportal sucht weiter nach definierten Tags, ab der Stelle nach dem eingefügten Text, also genau 1 Zeichen nach dem ...<tr><table><br>.
Nun könnte man sich wünschen, für verschiedene Code-Teile verschiedene Hintergrundfarben auszugeben und für besonders wichtige z.B. einen Rahmen herum zu machen. Natürlich könnte man dies durch die mehrfache Definition des "code"-Tags mit leichten Änderungen als "code1", "code2" etc. erledigen, aber es gibt einen besseren Weg: Die Verwendung von Parametern. Hier wie die Anwendung aussehen sollte:
<code bgcolor=e0e0e0 border=1> ... </code> |
baseportal übernimmt natürlich die Analyse und Bereitstellung der Parameter: Diese sind als einfache Variablen in der Tag-Definition verfügbar:
<table width=90% cellpadding=10 border=$border><tr><td bgcolor=$bgcolor><font size=3><pre>$_</pre></td></tr></table><br> |
Das ist alles... ;-) baseportal setzt an die Stelle der Variablen automatisch die übergebenen Parameter.
Allerdings stellt sich hier ein Problem: Wenn nun KEINE Parameter angegeben werden, wird für die Variablen NICHTS eingesetzt, es steht also ein ...border=><tr><td bgcolor=><font... im Text, was nicht nur unschön aussieht, sondern auch zu einem schwarzen Hintergrund führt. Ausserdem will man ja für die Standard-Fälle weiterhin nur <code> ohne Parameter angeben können. Man benötigt also Standard-Werte, falls nichts übergeben wurde. Das lässt sich mit einer eigenen Programmierung erledigen.
Man ist nicht auf einfache Ersetzungen angewiesen, sondern -wie in baseportal üblich ;-) - kann auch hier eine komplette Programmierung eingesetzt werden. Das komplette obige Beispiel für das "code"-Tag sieht z.B. so aus:
s/</</g; s/>/>/g; out '<table width=90% cellpadding=10'.($border ne ""?" border=$border":"").'><tr><td bgcolor='.($bgcolor ne ""?$bgcolor:"f0f0f0").'><font size=3><pre>$_</pre></td></tr></table><br>' |
Der Reihe nach:
s/</</g; |
Dies ist eine (einfache) "Regular Expression" mit Ersetzung ("Substitute"). Es bedeutet: "Suche ein <-Zeichen und ersetze es mit <. Mach dies mit allen <-Zeichen (durch das g am Ende, es bedeutet global)".
Normalerweise muss man die Variable auf die diese Ersetzung wirken soll vorne dran schreiben, z.B. so:
$text=~ s/</</g; |
Da es sich aber um die Variable $_ handelt, kann man dies auch weglassen: $_ ist eine "besondere Variable" - sie wird immer dann verwendet wenn man man eben keine Variable angibt. So kann man prägnantere Programme schreiben.
Der nächste Befehl ersetzt entsprechend alle >-Zeichen mit >. Der letzte Befehl bestimmt den Text der als Ersatz dienen soll. Er wird mit dem baseportal-typischen "out" ausgegeben. Dort drin "versteckt" befinden sich zwei spezielle Bedingungen:
($border ne ""?" border=$border":"") |
testet, ob $border leer ist und wenn nicht wird an dieser Stelle border=xxx eingesetzt, wobei xxx der Wert von ist. Ansonsten wird nichts eingesetzt.
($bgcolor ne ""?$bgcolor:"f0f0f0") |
ist fast dasselbe, nur dass hier, wenn $bgcolor leer ist der Standardwert f0f0f0 eingesetzt wird.
Wie definiert man nun eigene Tags? Natürlich mit einer Datenbank... ;-) Diese ist eine ganz normale baseportal-Datenbank und enthält die Namen, die Typen und die Codes neuer Tags. Es können mehrere verschiedene Tag-Datenbanken angelegt werden - und somit für verschiedene Zwecke bereitstehen.
>> In der Bibliothek befindet sich die Definition einer Tag-Datenbank
Hier der mögliche Inhalt einer Tag-Datenbank:
Um eine Tag-Datenbank auf einer Seite einzubinden braucht es folgenden Code:
<?tags src="tag-db-name"?> |
tag-db-name ist dabei der Name der Datenbank die die Tags enthält. Wo dieser Code steht ist egal, sinnvollerweise sollte man ihn am Anfang der Seite schreiben. Es können auch mehrere Tag-Datenbanken eingebunden werden:
<?tags src="tag-db1"?> <?tags src="tag-db2"?> |
Die Reihenfolge ist wichtig, denn falls in "tag-db2" gleichnamige Tags vorkommen, überschreiben diese diejenigen in "tag-db1". Sie können allerdings angeben, ob sie dieses Überschreiben wollen. Durch die Angabe
<?tags src="tag-db2" tags="add"?> |
werden nur Tags übernommen, die noch nicht definiert sind.
Wichtig ist dies auch bei include: Standardmässig übernimmt eine eingebundene Seite alle Tag-Definitionen. Bei folgendem Code
<?tags src="tagdb"?> <include src="seite2"> ... |
können also in "seite2" alle in "tagdb" definierten Tags genutzt werden. Will man dies nicht, so muss man im include angeben, dass die Tags gelöscht werden sollen:
<include src="seite2" tags="base"> |
Somit sind nur die normalen baseportal-Tags gültig. Will man auch diese Tags verhindern, bedarf es der Angabe:
<include src="seite2" tags="clear"> |
Damit sind wirklich überhaupt keine Tags mehr definiert. Die Angabe dieser Parameter ist auch im <?tags...?> möglich. So könnte man in einer neuen Seite mit
<?tags tags="base"?> |
bestimmen, dass, auch wenn diese Seite mit bereits definierten Tags aufgerufen wird, keine Tags ausser den baseportal-Tags ausgeführt werden. Natürlich kann dabei auch gleich eine bestimmte Tag-Datenbank eingebunden werden:
<?tags src="spezialtagdb" tags="base"?> |
|
Um mögliche Namenskonflikte zu umgehen kann man Namensräume definieren. Dies funktioniert anders als in XML.
((in xml ist das so: xmlns:bla="http://..." <-- damit wird "bla" weltweit eindeutig (wg. url) spezifiziert...))
<?tags src="tag-db1" base="bla"?> <?tags src="tag-db2"?> |
Angenommen in beiden Tag-Datenbanken ist das Tag "code" enthalten, dann überschreibt die Definition in "tag-db2" zwar die in "tag-db1", jedoch kann mit
<bla:code> ... </code> |
trotzdem auf das Code-Tag von "tag-db1" zugegriffen werden.
Es gibt zwei vordefinierte Namensräume, nämlich noparse und baseportal.
- <noparse:code> entfernt das noparse: und gibt <code> weiter. Eine etwaige Definition von "code" wird also an dieser Stelle aufgehoben. Damit kann man also z.B. überschriebene HTML-Tags erreichen.
- <baseportal:loop> spricht immer das baseportal-eigene loop an, auch wenn das normale loop-Tag von einer Tag-Datenbank überschrieben wurde.
Nicht nur mit dem speziellen Namensraum "noparse" kann das Parsen von Tags verhindert werden, dies ist auch für ganze Bereich möglich:
<noparse> <h1>Meine Datenbank</h1> <do action=all> <code>Das hier ist Code</code> </noparse> |
Alle Tags innerhalb des <noparse>...</noparse>-Tags werden -durch baseportal- nicht bearbeitet (dazu zählen auch baseportal-Tags). Die < und >-Zeichen bleiben dabei natürlich so wie sie sind, d.h. der Browser interpretiert die Tags dann sehr wohl.
Die Umsetzung des noparse-Tags ist übrigens ganz einfach: ;-)
Allerdings ist dieses Tag bereits standardmässig in baseportal definiert.
Es können auch gezielt bestimmte Tags ausgeschaltet werden:
<noparse tags="loop,code"> ... </noparse> |
Hier werden nur die Tags "loop" und "code" nicht ausgeführt. Dies betrifft nur die allgemeinen Tags, nicht die durch einen bestimmten Namensraum bezeichneten Tags. Ein
<set1:loop>...</set1:loop> |
würde also trotzdem ausgeführt werden.
Hier wie eine Beispielseite mit XML-Tags aussehen könnte. Es handelt sich dabei nicht um eine "richtige" XML-Seite, da diverse Elemente fehlen und sie auch nicht wirklich XML-konform ist. Aber sie wird von baseportal "verstanden":
<?tags src="tags"?> <html><head><title>xml</title> </head><body bgcolor=ffffff> <h2>das ist ein xml-demo</h2> <code> hier steht code... nämlich z.b. $x++; oder loop { ... } aber auch html: <b>jaja</b> </code> <header bgcolor=e0e0e0>Mein Titel</header> </body></html> |
Zwei Typen kennt jeder der ein bisschen HTML kann: Die "leeren" Tags ohne Ende-Tag wie z.B. <br> und die "richtigen" Tags wie <b>...</b>, also die ein Anfangs- und Ende-Tag haben.
Hier eine Liste mit allen in baseportal verfügbaren Tag-Typen:
Typ | Beschreibung |
---|---|
tag | normales Tag mit Ende-Tag. Darin enthaltene Tags werden nicht bearbeitet (z.B. <code>...</code>). |
tag parse | normales Tag mit Ende-Tag. Das Tag wird bearbeitet, dann werden die, in dem daraus resultierenden Text, enthaltenen Tags ebenfalls bearbeitet (z.B. <loop>...</loop>). |
tag preparse | normales Tag mit Ende-Tag. Erst werden die darin enthaltenen Tags bearbeitet, dann wird dieses Tag bearbeitet. |
empty | einfaches Tag ohne Ende-Tag. Im daraus resultierenden Text enthaltene Tags werden nicht bearbeitet (z.B. <br>). |
empty parse | einfaches Tag ohne Ende-Tag. Im daraus resultierenden Text enthaltene Tags werden bearbeitet (z.B. <do action=all>). |
regex | "Regular Expression" - ein beliebiges Suchmuster. |
regex parse | "Regular Expression" - ein beliebiges Suchmuster. Im daraus resultierenden Text enthaltene Tags werden bearbeitet. |
Hier die Erklärung:
Ein einfaches Tag ohne Ende-Tag, wie z.B. <img src="..."> oder <do action=all>
Ein normales Tag mit Ende-Tag. Es heisst "parse", weil man (normalerweise) die neu definierten Tags auch ineinander verschachteln möchte. Beispiel:
<loop> Und hier der HTML-Text: <code> $HTML </code> </loop> |
Hier wird "loop" gefunden und ausgeführt. Die Ausgabe wird wiederum analysiert und gefundene Tags ebenfalls ersetzt, wie hier das "code"-Tag.
Bei unserem "code"-Beispiel ist das Verhalten von obigem "parse" nicht gewünscht, weil z.B. in folgendem Code das <do action=all> ja nicht ausgeführt werden soll:
<code> <h1>Meine Datenbank</h1> <do action=all> </code> |
Während bei "parse" erst das aktuelle Tag ausgeführt/ersetzt und dann die Ausgabe analysiert wird, untersucht ein "preparse"-Tag zuerst die innen liegenden Tags und führt diese aus. Das Ergebnis wird an das darüberliegende Tag gegeben, das dann bearbeitet wird.
Bei obiger <loop><code>...</code></loop>-Verschachtelung würde also das "code"-Tag zuerst ausgeführt werden (Was allerdings in diesem Fall keinen Unterschied macht ;-) ).
"preparse" wird selten gebraucht, ein Anwendungsbeispiel ist ein automatisch erzeugtes Inhaltsverzeichnis:
<index> <h1>Passwort-Verwaltung</h1> ...text.... <h1>Mail-Versand</h1> ...text... <h1>Volltextsuche</h1> ...etc. </index> |
An der Stelle des neuen Tags "index" soll das Inhaltsverzeichnis eingefügt werden. Vorher muss "index" aber erstmal wissen, wieviele Themen (mit <h1>...</h1> markiert) es innerhalb des Abschnitts gibt: Also lässt es den inneren Text erstmal analysieren. "h1" muss nun ebenfalls neu definiert werden und in einer Variablen speichern, welche Themen es gibt. Dann erst wird "index" ausgeführt, dass nun einfach diese Variable auslesen und so ein Inhaltsverzeichnis erstellen kann - das Inhaltsverzeichnis auf dieser Seite wurde übrigens genauso generiert... ;-)
Hier die entsprechenden Definitionen in einer Tag-Datenbank:
"Reguläre Ausdrücke" (auf Englisch "Regular Expressions", kurz "Regex" oder auch nur "Re") ist eines der spannendsten Themen vor allem in Perl und ein weites Feld. Es dient zur Textanalyse und -bearbeitung und man kann damit vieles in nur einer Zeile erledigen, wofür man in anderen Sprachen Dutzende oder Hunderte bräuchte. Auch baseportal nutzt intensiv reguläre Ausdrücke, z.B. um die Templates zu bearbeiten. Mit diesem "Tag-Typ" (genau genommen ist das natürlich kein Tag) kann nach beliebigen Texten gesucht werden.
Einfaches und naheliegendes Beispiel: Man möchte ein bestimmtes Wort (z.B. "Achtung") im Text hervorheben. Die Umsetzung ist herzlich einfach:
Wo immer "Achtung" auf der Seite auftaucht, würde es jetzt Rot markiert werden. Um mehrere Wörter zu bestimmen, schreibt man z.B.:
Hier würden die baseportal-Befehle "get", "put", "mod", "chg" und "del" in einem Template automatisch blau markiert werden. Das macht natürlich nur in einer Beschreibung Sinn (z.B. der baseportal-Dokumentation ;-) ), nicht einem tatsächlichen Programm. Die | trennen verschiedene Textalternativen.
Um genau zu sein würden auch Teile mitten in Wörtern entdeckt werden, z.B. forGET. Um nun wirklich nur Wörter zu erkennen, müsste man schreiben:
Und jetzt sind wir schon mittendrin in den "regulären Ausdrücken": \b hat eine besondere Bedeutung: Es passt auf "Wortgrenzen". Die Klammern gruppieren die verschiedenen Wörter. Weitere Erläuterungen würden wieder mal den Rahmen sprengen, sorry... ;-)
Eine sinnvolle Erweiterungen dieses Beispiels ist übrigens die automatische Verlinkung zu einer Glossar-Datenbank, in der die Begriffe im Detail erklärt werden. Der Code müsste dann so aussehen:
<font color=red><a href="bbeta.pl?htx=/meinname/glossardb&Name==$_">$_</a></font> |
Einfach, nicht? ;-)
"Entities" definieren
Auch der XML-Standard erlaubt es, "freie" Ersetzungen zu definieren, allerdings in weitaus beschränkterem Masse als baseportal mit regex bietet. In XML benutzt man dazu sog. "Entities". Sie kennen sie wahrscheinlich schon aus HTML, das sind die "Sonderzeichen", die von & und ; umschlossen sind, also z.B. < oder © oder die Umlaute ä, ü etc. Hier 2 Beispiele und die Umsetzung in baseportal:
oder mit Programmierung:
Der Text...
Mein Name ist &myname; und es ist jetzt genau &jetzt; Uhr. |
...führt damit zu folgender Ausgabe
Mein Name ist Sepp Walchinger und es ist jetzt genau 03:59 Uhr. |
Hierzu gibt es eigentlich nicht viel zu schreiben, denn egal wo Sie ihre selbstdefinierten Tags verwenden - diese werden automatisch verarbeitet:
<perl> out "Dies gilt es zu beachten: <achtung>Wichtig!</achtung>"; </perl> |
Hier wird das eigene Tag "achtung" genauso behandelt wie wenn es direkt im Template stehen würde.
Selbst in Datenbank
Angenommen man erstellt eine Datenbank mit Texten, die selbstdefinierte Tags enthalten. Nun möchte man beiMan liest diese ein etc. die müssen dann auch geparsed werden... Bei der baseportal-Dokumentation ist das der Fall...
<do action=all><perl> |
Wenn Sie so wollen, können Sie sich vorstellen, der Browser könnte die neuen Tags wirklich verstehen.
Mit
tags "tag-db"; |
wird die "Tag-Definitionsroutine" aufgerufen....
((kommt noch))
Eine der grossen Stärken von XML (richtig angewandt) ist, dass man aus ein- und derselben Datenbasis unterschiedliche Ausgaben für verschiedene Formate erzeugen kann - ohne irgendetwas an den Seiten zu ändern. Im folgenden wird gezeigt, wie aus einer XML-Seite die Ausgabe für HTML, WAP und einfachen Text erzeugt wird.
Wem sich der Vorteil hier nicht gleich erschliesst, möge sich vor Augen halten, dass er vielleicht Hunderte von Seiten erstellt hat, die er nun durch das Anpassen eines einzigen Tag-Satzes automatisch ALLE in ein neues Format wandeln kann!
Hier die XML-Seite, der Ursprung für alle anderen Seiten:
<?tags src="html"?> <header titel="Adressen"/> <einleitung> Hier ist meine persönliche Adressenliste. </einleitung> <adressen> <person> <name>Hans Huber</name> <strasse>Waldweg 3</strasse> <ort>12345 Berlin</ort> <telefon>030 / 12345678</telefon> </person> <person> <name>Andrea Aal</name> <strasse>Zossener Str. 9a</strasse> <ort>10999 Berlin</ort> <telefon>030 / 98765431</telefon> </person> </adressen> &disclaimer; <footer/> |
In der eigentlichen XML-Seite sollte kein "Format-spezifischer" Code vorkommen, wie einleitende oder abschliessende Tags (z.B. <html><head><title>... in HTML). Da wir sie in einer vernünftigen HTML-Seite und entsprechendes in einer wohlgeformten WAP-Seite brauchen, verwenden wir dafür die alleinstehenden Tags "header" (dem wir noch den Titel als Parameter mitgeben) und "footer".
|
Hier nun die Tag-Datenbank für die HTML-Ausgabe:
Im header wird der Parameter "titel" entsprechend eingesetzt. adressen baut eine Tabelle um die Ausgabe der Personen, der Rest sollte klar sein.
Und das ist die HTML-Seite die erzeugt wird:
<html><head><title>Adressen</title></head><body bgcolor=ffffff> <h2>Adressen</h2> <p><i> Hier ist meine persönliche Adressenliste. </i></p> <table bgcolor=e0e0e0 cellpadding=4 cellspacing=0> <tr align=middle bgcolor=d0d0d0><td>Name</td><td>Strasse</td><td>Ort</td><td>Telefon</td></tr> <tr> <td><b>Hans Huber</b></td> <td>Waldweg 3</td> <td>12345 Berlin</td> <td>030 / 12345678</td> </tr> <tr> <td><b>Andrea Aal</b></td> <td>Zossener Str. 9a</td> <td>10999 Berlin</td> <td>030 / 98765431</td> </tr> </table> <p align=center><font size=2>Ich distanziere mich von den Inhalten aller weiterführenden Links!</font></p> </body></html> |
Hier nun die Tag-Datenbank für die WML-Ausgabe:
Der anfängliche Perl-Abschnitt im header ist notwendig, damit baseportal die Seite auch als WAP-Seite schickt, sonst können WAP-Browser die Seite garnicht verstehen. Ansonsten wird ebenfalls mit dem "titel"-Parameter ein entsprechender "Seitenkopf" erzeugt. Der "Disclaimer" wird in diesem Beispiel weggelassen, da WAP-Handys sowieso so wenig Platz auf dem Display haben. Die Definition von disclaimer (mit leerem "Code"-Feld) ist aber notwendig, denn sonst würde &disclaimer; einfach so in der Seite stehen bleiben. Die restlichen Tags entsprechen in etwa denjenigen bei HTML.
Und das ist die WML-Seite die erzeugt wird:
<perl> $_header="Content-type: text/vnd.wap.wml\n\n"; </perl> <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card title="Adressen"> <b>Adressen</b> <p><i> Hier ist meine persönliche Adressenliste. </i></p> <table columns=4> <tr><td>Name</td><td>Strasse</td><td>Ort</td><td>Telefon</td></tr> <tr> <td><b>Hans Huber</b></td> <td>Waldweg 3</td> <td>12345 Berlin</td> <td>030 / 12345678</td> </tr> <tr> <td><b>Andrea Aal</b></td> <td>Zossener Str. 9a</td> <td>10999 Berlin</td> <td>030 / 98765431</td> </tr> </table> </card></wml> |
Und zum Schluss die Tag-Datenbank für die reine Text-Ausgabe:
Hier setzen wir nun etwas Perl-Programmierung ein, um beim header den Titel komplett GROSS zu schreiben. Einen footer brauchen wir nicht. Die meisten anderen Tags geben einfach ihren Inhalt unverändert weiter ($_). Bei adressen werden noch überflüssige Zeilenumbrüche und Tabs entfernt.
Und das ist die (zugegeben sehr schlichte) Text-Seite die erzeugt wird:
ADRESSEN Hier ist meine persönliche Adressenliste. Hans Huber, Waldweg 3, 12345 Berlin, 030 / 12345678 Andrea Aal, Zossener Str. 9a, 10999 Berlin, 030 / 98765431 --- Ich distanziere mich von den Inhalten aller weiterführenden Links! --- |
Mancher wird sich bei diesem Beispiel verwundert die Augen reiben: Nanu, das ist doch eigentlich hervorragend für eine Datenbank geeignet - und genau dafür gibt es doch baseportal... Richtig! ;-)
Hier zerfliessen die Grenzen zwischen einem Datenbank-System wie baseportal und XML - letzteres wurde u.a. so gestaltet, dass es auf der einen Seite einfach aus Datenbanken generiert und auf der anderen Seite leicht in Datenbank integriert werden kann.
Natürlich sollte man die Personen mit einer entsprechende baseportal-Datenbank verwalten und dann mit <loop>...</loop> in die Seite einbinden... ;-)
baseportal entspricht aus verschiedenen Gründen keinem "reinen" XML. Trotzdem kann man problemlos 100% XML-konforme Seiten erstellen. Die Betonung liegt auf kann - man muss aber nicht ;-)
Insgesamt verfolgt der XML-Standard (und was dazu gehört) folgenden Ansatz:
|
Die DTD (oder jetzt neu: "XML Schemas") definiert die Regeln für die Tags, d.h. wie sie heissen, wann sie erlaubt sind und welche Parameter dazu gehören. Sie sagt allerdings NICHTS über deren Aussehen und Funktion aus, das übernehmen XSL -eine "Stil"-Sprache, die beschreibt, wie Tags dargestellt werden sollen, vergleichbar mit CSS- und XSLT, ein neues und recht kompliziertes Sprachkonstrukt zur Umwandlung von XML.
|
baseportal macht das (natürlich ;-) ) einfacher und bequemer: Die DTD fällt weg, wenn Parameter vorhanden sind, werden diese analysiert und deren Werte übergeben - was damit genau passiert ist völlig der Tag-Definition überlassen. Um nun ein neues Tag zu definieren braucht man nicht mehr, als den Namen und die Auswirkungen.
|
Da baseportal aber auch mit allen XML-Notwendigekeiten klarkommt, sollte man -um XML-konform zu schreiben- folgende Regeln einhalten:
Die Regeln 1, 3 und 5 tun nicht weiter weh, bei Regel 2 gibt es Schwierigkeiten mit Browsern, die kein XML verstehen (auch wenn man dies durch ein Leerzeichen vor dem abschliessenden /> mildern kann), die Regel 4 kann man später immer noch beachten/hinzufügen ;-)
Mehr zu Regel 1 im folgenden Punkt...
Besserer Parser | Nach oben |
<loop Strasse=="Am Wald 3"> |
Das ist aber nicht zwingend notwendig, also geht weiterhin:
<loop Strasse==Am\ Wald\ 3> |
Allerdings ist klar, dass Strasse=="Am Wald 3" lesbarer ist. Ausserdem entspricht es damit dem XML-Standard; in XML müssen Parameter immer in Anführungsstrichen stehen. Ebenso können in Anführungsstrichen (fast) alle anderen Zeichen verwendet werden, die sonst (mit vorangestelltem \) "escaped" werden müssten:
<loop code="bla=3 & blubber=5"> |
Dies gilt allerdings NICHT für das >-Zeichen. Auch Anführungsstriche innerhalb von Anführungsstrichen müssen Sie besonders behandeln:
<loop Alter\>=18 text="Er sagte: \"Nein!\""> |
Das gilt auch für den (seltenen) Fall, dass Sie in einem Wert ein $-Zeichen abfragen wollen und somit KEINE Variable meinen:
<loop nickname=="billion\$man"> |
Da bei baseportal auch Feldnamen, die z.B. Leerzeichen enthalten können, als Parameter möglich sind, können Sie auch hier Anführungsstriche verwenden:
<loop "Vorname / Nachname"=="Huber / Hans"> |
Sie können jetzt -zur besseren Strukturierung- Parameter in mehrere Zeilen schreiben:
<do action=all Name~=a sort=- data_back=a00000 data_color=eeeeee head_back=0000a0 head_color=ffffff > |
Das alleinstehende Grösser-Zeichen > in der letzten Zeile ist der Abschluss des <do action=all-Tags in der ersten Zeile.
|
Wie man es von verschiedenen HTML-Tags her kennt, gibt es nun auch "alleinstehende" Parameter, wie z.B. hier:
<td nowrap> |
Nutzt man einen solchen alleinstehenden Parameter in selbstdefinierten Tags, so wird die gleichnamige Variable einfach auf den Wert 1 gesetzt. Beispiel einer Tag-Definition:
Name: mark Code: $_="<b>$_</b>" if $strong; "<font color=red>$_</font>" |
Hier würde mit
<mark strong>Bitte beachten Sie:</mark> blabla... |
folgender Text ausgegeben:
Bitte beachten Sie: blabla... |
Der XML-Standard definiert, dass bei Tags, die kein Ende-Tag haben (also so etwas wie <img src=...> oder <do action=all...>) vor dem abschliessenden >-Zeichen ein Backslash / stehen MUSS. In baseportal ist es erlaubt, aber kein Zwang. Will man das / vor dem >-Zeichen einem Parameter zuordnen, so muss man es mit \ "escapen":
<meintag param=mit/> |
würde den Parameter param auf "mit" setzen, während bei
<meintag param=mit\/> |
der Wert "mit/" zugewiesen wird. Eigentlich sollte man aber (sowieso) besser Anführungsstriche verwenden:
<meintag param="mit/"> |
Namensräume | Nach oben |
Bisher gab es einige Probleme bei Mehrfachaufrufen von Datenbanken, z.B. mit dem <do action=all>
<p>Aufruf 1:</p> <do action=all Name~=a> <p>Aufruf 2:</p> <do action=all Name~=b> |
Dies führte bisher zu dem Problem, dass beim ersten Aufruf die Abfrage noch gänzlich ungesetzt war, also die gewünschte Ausgabe kam. Beim zweiten Aufruf war der ursprüngliche Aufruf jedoch noch sichtbar, d.h. die Abfrage des zweiten Aufrufs lautet in Wirklichkeit Name~=a & Name~=b, was natürlich NIE erfüllt sein kann.
In der neuen Version werden nun die Parameter von Tags untereinander abgegrenzt. Hier ein kurzes Programm, das den Geltungsbereich von Parameter zeigt:
(aussen1) bla=$bla, blubb=$blubb, urx=$urx<br> <perl bla=aaa blubb=xxx urx=7> $global=1; my $lokal=2; out "(perl1) bla=$bla, blubb=$blubb, urx=$urx, global=$global, lokal=$lokal<br>"; </perl> <perl blubb=999> out "(perl2) bla=$bla, blubb=$blubb, urx=$urx, global=$global, lokal=$lokal<br>"; </perl> (aussen2) bla=$bla, blubb=$blubb, urx=$urx, global=$global, lokal=$lokal<br> |
Auch das <perl>...</perl> ist ein ganz normales Tag, dem Parameter übergeben werden können, die dann innerhalb des Tags als einfache Variablen (mit $ vorne dran) zur Verfügung stehen - ebenso wie von Anfang an alle Parameter die per URL/FORM übergeben wurden.
Ruft man das Programm nun mit der Parameter-Übergabe "urx=5", also
http://...?htx=/name/seite&urx=5 |
auf, führt dies zu folgender Ausgabe:
(aussen1) bla=, blubb=, urx=5 (perl1) bla=aaa, blubb=xxx, urx=7, global=1, lokal=2 (perl2) bla=, blubb=999, urx=5, global=1, lokal= (aussen2) bla=, blubb=, urx=5, global=1, lokal= |
Bei "aussen1" sind bla und blubb natürlich noch leer, während urx den Wert "5" von der URL übernimmt.
Beim 1. Perl-Tag ("perl1") werden alle drei Variablen auf andere Werte gesetzt - allerdings nur lokal innerhalb dieses Tags, denn wie man an der Ausgabe des 2. Perl-Tags ("perl2") sieht, ist bla nun wieder leer und urx hat wieder den Wert "5" aus der URL. blubb erhält zwar einen anderen Wert, wird aber nach Beendigung des 2. Perl-Tags ebenfalls wieder auf seinen ursprünglichen Wert zurückgesetzt, also wieder geleert.
Die im 1. Perl-Tag gesetzt Variable global behält die ganze Zeit über ihren Wert, da sie nicht als Parameter in einem Tag übergeben wurde. Wollen Sie, dass eine Variable nur lokal in einem Tag definiert ist, müssen Sie ein my vor der ersten Zuweisung schreiben, so wie bei der Variable lokal in diesem Beispiel.
Werte abfragen | Nach oben |
put gibt in %_put die tatsächlich geschriebenen Werte zurück:
put ["Name", "Sepp4", "Telefon", 9999]; out "Id=$_put{Id}, Name=$_put{Name}, Telefon=$_put{Telefon}"; |
könnte z.B. folgende Ausgabe liefern:
Id=5, Name=Sepp4, Telefon=9999 |
Da man ja weiss, welche Werte man an das put übergeben hat, ist die Abfrage von %_put hauptsächlich zum Ermitteln der Id wichtig. Sinnvoll ist es darüber hinaus bei Default-Werten oder wenn Werte beim Eintrag verändert werden, z.B. bei einem Zahlfeld, das auf 2 Nachkommastellen eingestellt ist:
my $put=put ["Zahl", 3.1415926, "Datum", "jetzt"]; out "Zahl=$_put{Zahl}, Datum=$_put{Datum}"; |
würde als Ausgabe z.B.
Zahl=3.14, Datum=14.4.2001, 00:15 |
ergeben. Mehrfacheinträge gehen natürlich auch:
put { "Name" => ["Andrea", "Beate", "Christoph"], "Telefon"=> [1234,5678,9012] }; out <<EOF; Id=$_put{Id}[0], Id=$_put{Id}[1], Id=$_put{Id}[2], EOF |
Liefert die 3 vergebenen Id's der Einträge. Oder (für die echten Perl-Freaks ;-) ) die Ausgabe als einzeilige Schleife:
out "Id=$_, " foreach (@{$_put{Id}}); |
Nach einem get steht das Ergebnis in einem Hash mit dem gleichen Namen wie die Datenbank zur Verfügung:
get "Id==*", "meinedb"; for(my $i=0; $i<$_amount; $i++) { out $meinedb{Feldname}[$i]," "; } |
Gibt man einen Ergebnisnamen an, so wird dieser als Hashname verwendet:
get "Name~=a", "meinedb", "ergebnis1"; get "Name~=b", "meinedb", "ergebnis2"; for(my $i=0; $i<$ergebnis1{_amount}; $i++) { out $ergebnis1{Feldname}[$i]," "; } for(my $i=0; $i<$ergebnis2{_amount}; $i++) { out $ergebnis2{Feldname}[$i]," "; } |
Neben der in Perl üblichen Möglichkeit Hashes mit $hash{Name} anzugeben, können Sie im HTML-Code auch eine andere, ein wenig einfachere Variante verwenden:
<perl> $hash{Name}="Georg Griebig"; </perl> Mein Name ist: $hash{Name}<br> Ich wiederhole, mein Name ist: $hash:Name<br> Der Wert von "cmd" ist: $_get:cmd |
Dies rührt daher, da XML-Namensräume direkt Perl-Hashes entsprechen.
|
Innerhalb eines loop werden die Werte automatisch durch den Ausgabefilter gewandelt. Dies bewirkt z.B. bei einem EMail-Feld, dass ein <a href="mailto:...">...</a>-Link um die EMail-Adresse herum gesetzt wird oder bei einem Datumsfeld die Wandlung in das angegebene Format. Will man innerhalb einer loop-Schleife auf den eigentlichen "rohen" Wert zugreifen, so kann man dies mit %_raw:
<loop> Name: $Name<br> EMail: $_raw:EMail<p> </loop> |
...oder innerhalb eines "Perl"-Codes:
<loop code=perl> out <<EOF; Name: $Name<br> EMail: $_raw{EMail}<p> EOF </loop> |
Der Befehl get holt alle Werte immer im "Rohformat", ohne sie durch den Ausgabefilter zu wandeln. Es gibt aber einen neuen Befehl, der wie loop die Ergebnisse sofort wandelt:
<perl> getf "Name==!", "db"; out "Der Name lautet $Name und das Datum ist $Datum<br>"; </perl> |
Fehlerbehandlung | Nach oben |
Standardmässig gibt baseportal Fehler direkt an der Stelle der HTML-Seite aus, an der der Fehler passiert ist. Die Fehlermeldungen können genauso wie alle anderen Ausgabetexte mit set_language auf eine andere Sprache umgestellt oder beliebig umdefiniert werden (s. Anhang).
Tritt bei der Ausführung eines baseportal-Befehls ein Fehler auf, so bricht dieser üblicherweise ab und gibt den Wert undef zurück. Ein Test ob ein Befehl erfolgreich war sieht demnach so aus:
if(put ["Name", "Stefan"], "kunden") { # Befehl wurde erfolgreich ausgeführt } else { # Während des Befehls ist ein Fehler aufgetreten } |
Schreibt einen neuen Eintrag in die Datenbank kunden - tritt dabei ein Fehler auf, wird darauf entsprechend reagiert.
Üblich ist auch folgende Schreibweise:
put ["Name", "Stefan"], "kunden" or out "FEHLER!"; |
Gibt FEHLER! aus, wenn ein Fehler aufgetreten ist.
Um die baseportal-eigene Fehlerausgabe zu unterbinden, muss man die Variable $_error_mode auf no setzen.
Variable | Beschreibung |
---|---|
$_error | Fehlername des letzten Fehlers (s. Anhang) |
$_error_text | Ausführliche Fehlerbeschreibung des letzten Fehlers in der ausgewählten Sprache |
$_error_from | Funktion in der der Fehler aufgetreten ist |
$_error_mode | ungesetzt/leer=Fehler an der Stelle des Auftretens ausgeben top=gesammelt zu Beginn bottom=gesammelt am Ende no=keine Fehler ausgeben |
@_error | Alle gesammelten (noch nicht ausgegebenen) Fehlernamen |
@_error_text | Alle gesammelten (noch nicht ausgegebenen) Fehlerbeschreibungen |
$_error_handler | Übergebene Routine wird im Fehlerfall ausgeführt |
Durch den Aufruf der Routine error kann von Hand ein beliebiger Fehler erzeugt werden:
error "Es ist ein unglaublich schlimmer Fehler aufgetreten!"; |
error gibt selbst undef zurück. Um den fehlerhaften Abbruch einer Unterroutine anzuzeigen bietet sich folgende Schreibweise an:
sub my_sub { my($val)=@_; return error "Der erste Parameter darf nich leer sein!" if $val eq ""; ...code... 1; } |
Gibt die Fehlermeldung Der erste Parameter darf nicht leer sein! aus und kehrt mit einem undef zurück, wenn der übergebene Parameter leer war. Ist alles fehlerfrei gelaufen, gibt die Routine 1 - logisch wahr zurück. my_sub verhält sich damit wie alle baseportal-Befehle.
Durch die Definition einer eigenen Fehler-Routine kann selbst auf Fehler reagiert werden. Ein Verweis auf die Routine muss an $_error_handler übergeben werden. Diese wird dann aufgerufen, wenn ein Fehler auftritt. Als erster Parameter wird der Fehlername übergeben, gefolgt von weiteren Angaben. Beim Fehler perl_error ist dies zum Beispiel der Text des Perl-Fehlers.
Ist der Rückgabewert logisch falsch (also 0 oder leer oder undef), so wird danach die baseportal-eigene Fehlerroutine ausgeführt, bei logisch wahr (jeder andere Wert, z.B. 1) nicht.
$_error_handler=sub { put $_error_text, "error_log.htx"; 0; } |
Protokolliert alle aufgetretenen Fehler in der Datei error_log mit. Aufgrund des Rückgabewerts 0 wird danach die baseportal-Fehlerroutine aufgerufen und der Fehlertext also wie normal ausgegeben. Der Nutzer merkt keinen Unterschied.
Sonstiges | Nach oben |
outf "Fliesskomma-Zahl mit 2 Nachkomma-Stellen: %.2f", 4.5678; |
Mehr in der Perl-Doku unter "printf" ;-)
Ausser Verzeichnissen werden nun alle "Datenfiles" zusammen sortiert ausgegeben (vorher waren Datenbanken und Seiten getrennt), neue Datenfiles sind Archive und Nutzerdatenbanken...
Es kann nun ganz einfach jede zweite Zeile einer Tabelle anders gefärbt werden:
<do action=all databack2=f0f0f0> |
per datenbank -> da müsste man gleich eine tabelle für die doku draus machen...
Probleme / Unklar | Nach oben |
$_amount etc. Automatisch am Anfang eines htx setzen (init ist nicht mehr notwendig) -> ist das wirklich sinnvoll? - Es ist ein wenig aufwendig umzusetzen und nicht jeder brauchts....
Allgemeine Erklärungen | Nach oben |
Der Unterstrich am Anfang einer Variablen, eines Parameters oder eines Feldnamens bedeutet, dass es sich um eine spezielle baseportal-Variable handelt. etc. blabla - auch wenn es möglich ist, sollten sie nie (nirgendwo ;-) ) den Unterstrich zu Beginn eines Namens verwenden.
Gibt man mehrere Parameter an, so kann der Unterstrich bei den folgenden weggelassen werden. Die folgenden Zeilen bedeuten alle dasselbe:
"_down,file,join" "_down file join" "_down_file_join" "_down,_file,_join" "_down, file, join" "_down _file _join" "_down, _file, _join" |
Reste | Nach oben |
((listen für move))
move ["seite.htx", "db1", "db2", "dir1/*"], "/meinname/test/dir2/"; |
Verschiebt die Seite seite, die Datenbanken db1 und db2, sowie alle Dateien und Datenbanken aus dem Verzeichnis dir1 in das Verzeichnis /meinname/test/dir2.
move ["a.htx", "b.htx", "c.htx"], ["x.htx", "y.htx"]; |
Benennt die Seiten a und b in x und y um. Da für c kein Wert mehr in der Liste steht, wird dies einfach ignoriert.
move ["a.htx", "b.htx", "c.htx"], "all_in_one.htx"; |
Stehen auf der linken Seite mehrere Dateien und auf der rechten Seite nur eine Datei, so werden die Dateien der linken Seite zu einer einzigen zusammengefasst.
move ["db1", "db2", "db3"], "all_in_one_db"; |
Stehen auf der linken Seite mehrere Dateien und auf der rechten Seite nur eine Datei, so werden die Dateien der linken Seite zu einer einzigen zusammengefasst.
|
Sie können statt eines festen Wertes auch Perl-Code in jedem beliebigen Datenbank-Feld speichern. Beim Lesen des Feldes wird der Code dann ausgeführt und der zurückgegebene Wert als Inhalt verwendet.
Um Perl-Befehle in ein Feld zu schreiben müssen Sie den Code einfach in geschweifte Klammern setzen: { ... }. Leerzeichen vor der öffnenden Klammern oder hinter der schliessenden sind nicht erlaubt, sonst wird es als normaler Text gewertet.
|
Beispiele:
put ["Name", "Hans", "Nummer", '{++$cnt;}', "Abgelaufen", '{ datum(.... |
--> zugriff auf andere felder -- wie bei excel! (A1 und so kram)
(( da ich das mit dem code ja erstmal fürs serial brauche, kann ichs ja vorerst noch verstecken und dann später schaun wie ich das am besten implementiere und obs sinn macht... ))
--> ach ja und "Fehler: (perl) Fehlerhafter Perl Code in 0:
0 >> Mehr Info" (von xml) is was anderes als das hier mit {...}, weil dasmit {...} VOR dem _get ausgeführt wird...
Beim Lesen der Datenbank ist nicht ersichtlich, wie der Feldinhalt zustande kam, d.h. es wirkt "nach aussen" so, als ob tatsächlich der errechnete Wert im Feld stünde. Der eigentliche Code steht (wie üblich) in %_raw:
get "Id==3", "db1"; out $_raw{Nummer}; |
(( Code in Dateien speichern = blödsinn, da tuts ein put ... und ein 'eval get "bla.htx";' genauso - das extra zu verstecken (also das man 'get "bla.htx"' macht und es kommt erzeugter code) -- macht das sinn?????? ich weiss nich ))
Das Feld Kinder enthält dabei einen Verweis auf die gespeicherte Liste, deshalb muss @$Kinder geschrieben werden. Falsch wäre es ohne das $-Zeichen, denn damit würde die Liste @Kinder angesprochen werden, was (offensichtlich) etwas anderes ist.
Beim Speichern wird jedes einzelne Element der Liste auf etwaige Bedingungen geprüft; ebenso wird beim Auslesen jedes einzelne Element der Liste behandelt:
put ["EMails", ["abc@blubb.de", "jaja@sowas.de", "xxx"] ]; |
Angenommen das Feld EMails ist als Typ Email definiert, so wäre das dritte Element xxx der Liste kein gültiger Wert - daraufhin wird der komplette Eintrag zurückgewiesen.
---
Bei Hashes wird nur der Wert bzgl. des Feldtyps behandelt, nicht der Schlüssel:
put ["EMails", {"yahoo" => "huber@yahoo.de", "gmx" => "huber@gmx.de", "t-online" => "sepp.huber@t-online.de"} ]; |
Ist das Feld EMails als Typ Email definiert, so ist der Eintrag insgesamt in Ordnung, da die Schlüssel yahoo, gmx und t-online nicht als EMail-Adr. getestet werden.
© 2000 baseportal.de. Alle Rechte vorbehalten. Nutzungsbedingungen |