![]() |
Andreas Waldemar Wawrzinek:
|
|
| |
| E-Mail: |
|---|
Bei Fragen zu diesem Beitrag bitte den Autor des Beitrags kontaktieren!
Dynamische Webseiten haben einen immer größeren Stellenwert in unserer Internetlandschaft. Inhalte und Strukturen werden dabei jedoch oft auch "on-the-fly" aus Datenbanken generiert. Dieser Artikel zeigt das Prinzip, wie eine umfangreichere Navigationsstruktur aus einer Datenbank dynamisch generiert werden kann.
Der Beitrag setzt dazu auf dem Artikel von Lutz Eymers DHTML-Artikel
Sitemap mit JavaScript und Layers auf. Jenen Artikel sollten Sie daher gelesen haben, bevor Sie sich auf diesen hier stürzen.
Das Ziel ist es, die Daten für den Sitemap-Verweisbaum aus einer MySQL-Datenbank zu gewinnen. In der Praxis kann eine solche Trennung sinnvoll sein, z.B. wenn Redakteure, die den Sitemap-Tree pflegen, nichts von JavaScript verstehen oder nicht direkt die Webseiten bearbeiten dürfen, sondern über ein Frontend mit der Datenbank arbeiten.
Aus unsortierten Datenbank-Tabellenelementen wird dabei eine logisch strukturierte Sitemap erstellt. Als serverseitige Skriptsprache wird Perl verwendet. Als Plattform wird in diesem Artikel Windows NT/2000 genutzt, wobei die Applikation dank der Plattformunabhängigkeit von Perl aber ebenso auf Linux/Unix laufen sollte.
Ich gehe davon aus das MySql, Apache und Perl in ihrer Grundkonfiguration, also auf "Hallo Welt" - Niveau, auf dem Rechner läuft. Hier trotzdem noch einmal die Software-Quellen:
| Apache: | |
| Mysql: | |
| Perl: |
Alle Distributionen beinhlate sehr gute Dokumentation. Bei Mysql bietet es sich an, Mysql in von der Installationsroutine vorgeschlagenen Pfad zu installieren, ansonsten läßt sich MySQL nur durch das Editieren d
er my.ini Datei als NT Service starten. Hier muß der Eintrag basedir geändert auf den neuen Rootpfad des Mysql Verzeichnisses gesetzt werden:
basedir=c:/my_path/mysql
Zuerst wird gezeigt, welchen Aufbau die MySQL-Datenbank hat, und wie sie erzeugt wird. Gewünscht wird folgende Datenbanktabelle:
+----+------+------+-----------------+-----------+------+-------+ | nr | id | p_id | title | sortorder | type | flag | +----+------+------+-----------------+-----------+------+-------+ | 1 | 0 | -1 | root | 1 | 1 | true | | 3 | 3 | 0 | HTML | 1 | 1 | false | | 4 | 4 | 0 | SQL | 2 | 1 | false | | 5 | 5 | 0 | JAVA | 3 | 1 | false | | 6 | 6 | 0 | PERL | 4 | 1 | false | | 7 | 7 | 3 | HTML-FAQ | 3 | 1 | false | | 8 | 8 | 3 | HTML-LINK-1 | 1 | 1 | false | | 9 | 9 | 3 | HTML-LINK-2 | 3 | 1 | false | | 11 | 11 | 5 | JAVA-FAQ | 1 | 1 | false | | 12 | 12 | 6 | PERL-TOC | 2 | 1 | false | | 13 | 13 | 6 | PERL-LINK1 | 3 | 1 | false | | 14 | 14 | 6 | PERL-FAQ | 3 | 0 | false | | 19 | 19 | 14 | PERL-FAQ-1 | 4 | 0 | false | | 17 | 17 | 5 | JAVA-LINKS | 2 | 1 | false | | 18 | 18 | 5 | JAVA-Newsgroups | 4 | 1 | false | | 26 | 26 | 5 | JAVA-LINKs1 | 4 | 1 | false | | 41 | 41 | 4 | SQL-1 | 1 | 1 | false | | 36 | 36 | 14 | PERL-FAQ-2 | 4 | 0 | false | | 40 | 40 | 14 | PERL-FAQ-4 | 3 | 0 | false | | 37 | 37 | 14 | PERL-FAQ-3 | 4 | 0 | false | | 38 | 38 | 4 | SQL-Tutorial | 2 | 1 | false | +----+------+------+-----------------+-----------+------+-------+
Diese Daten können als SQL Skript abgebildet werden. Das SQL-Skript ist als Datei tree.sql in der
Download-Datei, die alle Ressourcen zu diesem Artikel beinhaltet, enthalten und wird in die Datenbank eingespielt.
# phpMyAdmin MySQL-Dump # http://phpwizard.net/phpMyAdmin/ # # Host: localhost Database : selfhtml # -------------------------------------------------------- # # Table structure for table 'tree' # CREATE TABLE tree ( nr int(11) NOT NULL auto_increment, id int(11), p_id int(11), title text, sortorder int(11), flag varchar(7) DEFAULT 'false', PRIMARY KEY (nr) ); # # Dumping data for table 'tree' # INSERT INTO tree VALUES ( '1', '0', '-1', 'root', '1', 'true'); INSERT INTO tree VALUES ( '3', '3', '0', 'HTML', '1', 'false'); INSERT INTO tree VALUES ( '4', '4', '0', 'SQL', '2', 'false'); INSERT INTO tree VALUES ( '5', '5', '0', 'JAVA', '3', 'false'); INSERT INTO tree VALUES ( '6', '6', '0', 'PERL', '4', 'false'); INSERT INTO tree VALUES ( '7', '7', '3', 'HTML-FAQ', '3', 'false'); INSERT INTO tree VALUES ( '8', '8', '3', 'HTML-LINK-1', '1', 'false'); INSERT INTO tree VALUES ( '9', '9', '3', 'HTML-LINK-2', '3', 'false'); INSERT INTO tree VALUES ( '11', '11', '5', 'JAVA-FAQ', '1', 'false'); INSERT INTO tree VALUES ( '12', '12', '6', 'PERL-TOC', '2', 'false'); INSERT INTO tree VALUES ( '13', '13', '6', 'PERL-LINK1', '3', 'false'); INSERT INTO tree VALUES ( '14', '14', '6', 'PERL-FAQ', '3', 'false'); INSERT INTO tree VALUES ( '19', '19', '14', 'PERL-FAQ-1', '4', 'false'); INSERT INTO tree VALUES ( '17', '17', '5', 'JAVA-LINKS', '2', 'false'); INSERT INTO tree VALUES ( '18', '18', '5', 'JAVA-Newsgroups', '4', 'false'); INSERT INTO tree VALUES ( '26', '26', '5', 'JAVA-LINKs1', '4', 'false'); INSERT INTO tree VALUES ( '41', '41', '4', 'SQL-1', '1', 'false'); INSERT INTO tree VALUES ( '36', '36', '14', 'PERL-FAQ-2', '4', 'false'); INSERT INTO tree VALUES ( '40', '40', '14', 'PERL-FAQ-4', '3', 'false'); INSERT INTO tree VALUES ( '37', '37', '14', 'PERL-FAQ-3', '4', 'false'); INSERT INTO tree VALUES ( '38', '38', '4', 'SQL-Tutorial', '2', 'false');
Bevor das Skript eingespielt werden kann, muss eine neue Datenbank erzeugt werden. Wir nennen unsere Beispieldatenbank Selfhtml. Zu allererst wird (unter Windows) die Eingabeaufforderung geöffnet (DOS Fenster). Dann wird in das mysql\bin-Verzeichnis gewechselt, und mit dem Befehl mysql der SQL-Editor gestartet.
Mittels create database selfhtml; wird eine leere Beispieldatenbank erstellt.
Das Ergebnis läßt sich mit show databases; anzeigen. Dabei wird die neue Datenbank mit den bestehenden Default Datenbanken angezeigt:
+----------+ | Database | +----------+ | mysql | | selfhtml | | test | +----------+ 3 rows in set (0.00 sec)
Die Daten liegen wie schon gezeit als SQL-Skript vor (
tree.sql). Ein solches SQL-Skript oder ein Datenbank-Dump stellt die Abbildung des Datenbank-oder Tabelleninhaltes als Abfolge von SQL Befehlen dar.
Mittels quit; wird zunächst der SQL-Editor verlassen.
Mit myqsl selfhtml < tree.sql wird anschließend das Skript aufgerufen, das mit seinen SQL-Befehlen vom Typ INSERT INTO den Inhalt der gewünschten Tabelle in die Datenbank selfhtml eingespielt. Dabei ist darauf zu achten, daß
die Datei tree.sql im aktuellen Verzeichnis liegt, ansonsten muß der Pfad mit angeben werden.
Mit C:\Programme\mysql\bin> mysql wird anschließend erneut der SQL-Editor aufgerufen.
Das Kommando use selfhtml; wählt die gewünschte Datenbank aus. Das SQL-Script tree.sql hat in der Datenbank die neue Tabelle angelegt, die wir uns zur Kontrolle ausgeben lassen wollen.
Mit show tables; werden alle Tabellen der Datenbank angezeigt.
Das Kommando select * from tree; gibt schließlich die
gewünschte Datenbanktabelle aus, die tree.sql erzeugt hat:
+----+------+------+-----------------+-----------+-------+ | nr | id | p_id | title | sortorder | flag | +----+------+------+-----------------+-----------+-------+ | 1 | 0 | -1 | root | 1 | true | | 3 | 3 | 0 | HTML | 1 | false | ... usw. siehe oben
Die Datenbank ist damit einsetzbar.
Die Applikation befindet in einem virtuellen Verzeichnis des Apache Webservers. Dazu sind einige Änderungen der httpd.conf, also in der Apache-Konfigurationsdatei, notwendig. Außerdem ist noch ein Eintrag in der hosts Datei von Windows zu tätigen, die im Windows-Verzeichnis liegt. Beide Dateien können Sie mit einem Texteditor bearbeiten.
In dieser Datei muß zum bestehenden Eintrag:
127.0.0.1 localhost
eine neue Zeile mit folgendem Eintrag hinzugefügt werden:
127.0.0.1 selfhtml.localhost
Die Kommentartexte in der Datei, die mit # beginnen, können stehen bleiben.
In der httpd.conf wird ein neuer Handler für die Extension der SSI's (Server Side Includes) mit eingfügt. Als Standard ist *.shtml angegeben. Mit dem neuen Handler lassen sich auch *.html Dateien als SSI Dateien ansprechen. Die Virtual Host Konfiguration ermöglicht zusammen mit der Host Datei, daß Dateien nun über http://selfhtml.localhost/ aufgerufen werden koennen. Außerdem läßt sich das Rootverzeichnis für jeden einzelnen Host beliebig verändern.
Options Includes ExecCGI;
Includes ermöglicht den Einsatz von Server Side Include (SSI) auf dem Server.
ExecCGI setzt generell das Ausführungsrecht für CGI Skripte.
Hier der Ausschnitt aus der httpd.conf, wie alles aussehen sollte. Die Pfade müssen Sie natürlich noch an Ihre Umgebung anpassen:
# New SSI Handler for the extension *.html
AddHandler server-parsed .html
#
# Configuration of the virtual Host.
#
<VirtualHost 127.0.0.1>
DocumentRoot "c:/wwwroot/apache/selfhtml"
ServerName selfhtml.localhost
ScriptAlias /cgi-bin/ "C:/wwwroot/Apachehttp://de.selfhtml.org/cgi-bin/"
<Directory "c:/wwwroot/apache/selfhtml">
Options Include
s ExecCGI
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
Bevor die Applikation installiert wird, müssen die nicht zur Standardinstallation von Perl gehörende Datenbankmodule nachinstalliert werden. Die kann bei der Active-State-Distribution von Windows-Perl bequem mit dem Perl Packet Manger (ppm) durchgeführt werden. In der DOS-Box ist dazu einfach der Befehl ppm einzutippen. Dieser startet den Perl Packet Manager.
Mit dem Befehl query läßt sich die List der installierten Module (Packages) auflisten. Sind die Module DBI und DBD-Mysql nicht vorhanden, so mössen sie nachinstalliert werden.
Das geschieht mit install DBI und install DBD-Mysql.
PPM holt sich, bei bestehender Internetverbindung, automatisch die Quellen und installiert diese in den korrekten Verzeichnissen.
Die Beispielanwendung besteht aus zwei Modulen und zwei Skripten.
Das Modul SqlBase.pm definiert die Basiskonfiguration.
Das Modul Sqlobj.pm beinhaltet die SQL Abfragen.
Das Script menu.cgi generiert die Seitenstruktur.
Das Script main.cgi gibt letztendlich nur Parameter aus und symbolisiert eine hypothetische Content-Seite.
Die Scripts werden nun im einzelnen vorgestellt.
Dieses Modul bzw. Packag
e inititert globale Variablen und importiert das Datenbankmodul DBI in die Applikation. Es definiert die Verbinungsvariable $self->{'dbh'}, den Pfad des Seitenwurzelverzeichnisse, den Namen der Tabelle, sowie den Pfad zum cgi-bin Verzeichnis.
use DBI;
#####################################################################
package Base
######################################################################
# ------------ SUPER CLASS CONSTRUCTOR
# ------------ INITS GLOBAL VARIABLES
sub new {
my $class = shift;
my %params = @_;
my $self = {};
# DATABASE CONECTION PARAMETERS
$self->{'db_connector'} = "DBI:mysql:database=selfhtml;host=localhost";
$self->{'db_username'} = "";
$self->{'db_password'} = "";
# START IDS FOR THE SITETREE
$self->{'userright_startid'} = "0";
$self->{'recursion_startid'} = "-1";
# TABLE AND PATH DEFINITIONS
$self->{'tbl_siteitem'} = "tree";
$self->{'siteroot'} = "/";
$self->{'path_cgi'} = $self->{'siteroot'}."cgi-bin/";
# CONNECTION TO DATABASE
$self->{'dbh'} = DBI->connect(
$self -> {'db_connector'},
$self -> {'db_username'},
$self -> {'db_password'},
{'RaiseError' => 1}) or die "Can't connect to database: $DBI::errstr\n";
bless $self, $class;
}
1;
Dieses Modul bzw. Package importiert das Modul SqlBase und erbt mit dem Befehl @ISA = qw(Base) dessen Eigenschaften. In der Methode sql_select_tree_childs_menu wird die SQL Abfrage
durchgeführt. Das Ergebnis wird zu einem String zusammengesetzt und an die aufrufende Methode zurückgegeben. Man könnte bei dieser kleinen Anwendung zwar auch alles in ein Skript packen, jedoch ist die modulare Aufteilung bei größeren Anwendungen, insbesondere bei Datenbankmigrationen, von Vorteil. Dann brauchen Sie nämlich einfach nur noch die Verbindungsparameter ändern und das Modul Sqlobj.pm einfach durch das Modul SqlOra.pm z.B. für Oracle ersetzen und die Anwendung läuft dann mit einer Oracle Datenbank, und die restlichen Skripte der Anwendung muessen nicht geändert werden.
use SqlBase;
######################################################################
# --------------------- SQL QUERIES FOR THE SITETREE
#####################################################################
package SqlGetTree;
# ------------------- INHERITATION FROM CLASS Base
@ISA = qw(Base);
# -------------------
sub sql_select_tree_childs_menu {
my $self = shift;
my $rec_id = shift ;
my $content;
my $sth;
my $ref;
my $query;
my $id;
my ( $p_id, $title, $sortorder, $flag, $physical_level);
$query = "SELECT t1.id, t1.p_id, t1.title, t1.sortorder,t1.flag
FROM $self->{'tbl_siteitem'} AS t1
WHERE p_id=$rec_id ORDER BY sortorder" ;
# ------------- SELECTS ALL PAGE ITEMS SORTED BY SORTORDER
$sth = $self->{'dbh'} -> prepare($query);
$sth->execute();
while ( $ref = $sth->fetchrow_arrayref() ) {
$content.= $ref->[0]."<separator>";
$content.= $ref->[1]."<separator>";
$content.= $ref->[2]."<separator>";
$content.= $ref->[3]."<separator>";
$content.= $ref->[4]."<separator>";
$content.= $ref->[5]."<separator>";
$content.$ref->[6]."\n";
}
$sth->finish();
# ------------- RETURNS QUERY RESULT AS A SORT OF XML - STRING ....
return $content;
}
sub sql_disconnect {
my $self = shift;
$self->{'dbh'}->disconnect();
}
# -------------------
sub delete {}
1;
Das Skript menu.cgi ist das dasjenige Script, welches letztendlich den Menübaum generiert, also den bis dahin statischen Teil. Das Skript greift auf das Modul Sqlobj.pm zu. Im package Main wird mit dem Aufruf $objref->rectree($startID) die Rekursion angestoßen. Vorher wird mit $objref=MENU->new() eine Instanz der Klasse Menu erzeugt. D.h. die Start ID der Rekursion wird an die Methode rectree() übergeben.
Mit dem Aufruf $self->{'sqlref'}->sql_select_tree_childs_menu($rec_id ) werden alle Kind-IDs aus der Datenbank gelesen. Alle gefunden Kind-IDs rufen dann für sich mit dem Aufruf $self->rectree ($id) wieder die Funktion rectree() auf und starten den Prozess erneut. Dies passiert so lange, bis alle Äste des Baumes durchlaufen sind. Alle Klarheiten beseitigt? Einfach ausprobieren!
#!perl
use strict;
use Sqlobj;
#
# PERL scripting for creating dynamic sitetrees.
# Copyright (c) 2001 Wawrzinek Waldemar [ waftschi@daybyday.de ]
#
# The client side Java Script is based on Lutz Eymers <ixtab@polzin.com> Sitemap Script.
#
# It's free to use, copy, m
odify, and distribute this software
# and its documentation for any purposes and without fee
# is hereby granted provided that this copyright notice
# appears in all copies.
#
# Of course, this software is provided "as is" without express or implied
# warranty of any kind.
#
#
package MENU;
sub new {
my $class = shift;
my %params = @_;
my $self = {};
$self->{'sqlref'} = SqlGetTree -> new();
bless $self, $class;
}
sub rectree {
my $self = shift;
my $rec_id = shift;
my $temp;
my $id;
my $p_id;
my $title;
my $flag;
my $type;
my $sortorder;
my $numOfChilds;
my $physical_level;
# Schleife durch alle ID's auf welche Variable $rec_id verweist
for ( split (/\n/, $self->{'sqlref'}->sql_select_tree_childs_menu( $rec_id ) ) ){
( $id, $p_id, $title, $sortorder, $type , $flag , $physical_level) = split(/\<separator\>/ , $_);
print " Note( $id , $p_id, '$title', '$self->{'sqlref'}->{'siteroot'}content.html?id=$id&p_id=$p_id&title=$title')\n";
# Funktion rectree ruft sich selbständig auf
$self -> rectree ($id);
}
}
######################################################################
package main;
my $objref;
my $startID = -1;
print "content-type: text/html\n\n";
print "\n\n\n\n";
$objref = MENU -> new ();
$objref ->rectree($startID);
$objref ->{'sqlref'}->sql_disconnect();
Das Perl-Script menu.cgi ersetzt die statischen Sitemap Definitionen
durch serverseitig aus einer My-SQL-Datenbank generierte Sitemap Definitionen.
Der Rest von Lutz Eymers' Sitemap-Script bleibt dabei unangetastet. Daher empfiehlt
es sich nur diese Script mittels
Server-Side-Includes
(SSI) anzusteuern. Aus diesem Grund wird der Definitionsteil im Script der Sitemap-Datei
sitemap.html (siehe unten) durch die folgende SSI-Anweisung ersetzt:
<!--#exec cgi="../cgi-bin/menu.cgi"-->Datei sitemap.html hat nun folgendes Aussehen (nur die relavanten Stellen werden hier dargestellt):
~~~~~~~~ SNIPP ~~~~~~~~ function initArray()
{
//<!-- --------- ../cgi-bin/menu.cgi GENERATES THE MENU STRUCTURE ---------- --> <!--#exec cgi="cgi-bin/main.cgi" --> //<!-- --------- ../cgi-bin/menu.cgi GENERATES THE MENU STRUCTURE END ---------- --> </body> </html> usw. ~~~~~~~~ SNIPP ~~~~~~~~
Noch einmal zusammengefaßt:
Diese Zip-Datei enthält die HTML- und Perldateien, das SQL Skript tree.sql, sowie alle erforderlichen Bilder.
Viel Spaß dabei! Der Waftschi
Tom's
object-oriented tutorial for perl