Skip to content

8. Anhänge

8.1. Tools für die Webentwicklung

Hier zeigen wir Ihnen, wo Sie die für die Webentwicklung erforderlichen Werkzeuge finden und wie Sie diese installieren. Bei einigen Werkzeugen haben sich die Versionen weiterentwickelt, und es kann sein, dass die hier gegebenen Erläuterungen für die neuesten Versionen nicht mehr zutreffen. Der Leser muss sich dann entsprechend anpassen... Im Webprogrammierungskurs werden wir im Wesentlichen die folgenden Werkzeuge verwenden, die alle kostenlos verfügbar sind:

  • einen aktuellen Browser, der XML anzeigen kann. Die Beispiele des Kurses wurden mit Internet Explorer 6 getestet.
  • ein aktuelles JDK (Java Development Kit). Die Beispiele des Kurses wurden mit dem JDK 1.4 getestet. Dieses JDK enthält das Java-Plug-in 1.4 für Browser, wodurch diese Java-Applets anzeigen können, die das JDK 1.4 nutzen.
  • Eine Java-Entwicklungsumgebung zum Schreiben von Java-Servlets. In diesem Fall ist es JBuilder 7.
  • Webserver: Apache, PWS (Personal Web Server), Tomcat.
    • Apache wird für die Entwicklung von Webanwendungen in PERL (Practical Extracting and Reporting Language) oder PHP (Personal Home Page) verwendet.
    • PWS wird für die Entwicklung von Webanwendungen in ASP (Active Server Pages) oder PHP verwendet
    • Tomcat wird für die Entwicklung von Webanwendungen mithilfe von Java-Servlets oder JSP-Seiten (Java Server Pages) verwendet
  • eine Datenbankverwaltungsanwendung: MySQL
  • EasyPHP: ein Tool, das den Apache-Webserver, die Sprache PHP und das SGBD MySQL zusammenführt

8.1.1. Webserver, Browser, Skriptsprachen

  1. Gängige Webserver
    • Apache (Linux, Windows)
    • Internet Information Server IIS (NT), Personal Web Server PWS (Windows 9x)
  1. Wichtigste Browser
    • Internet Explorer (Windows)
    • Netscape (Linux, Windows)
  1. Serverseitige Skriptsprachen
    • VBScript (IIS, PWS)
    • JavaScript (IIS, PWS)
    • Perl (Apache, IIS, PWS)
    • PHP (Apache, IIS, PWS)
    • Java (Apache, Tomcat)
    • Sprachen .NET
  1. Browser-seitige Skriptsprachen
    • VBScript (IE)
    • JavaScript (IE, Netscape)
    • PerlScript (IE)
    • Java (IE, Netscape)

8.1.2. Wo finden Sie die Tools?

Netscape
http://www.netscape.com/ (Link zu den Downloads)
Internet Explorer
http://www.microsoft.com/windows/ie/default.asp
PHP
http://www.php.net
http://www.php.net/downloads.php (Windows-Binärdateien)
PERL
http://www.activestate.com http://www.activestate.com/Products/
http://www.activestate.com/Products/ActivePerl/
Vbscript, Javascript
http://msdn.microsoft.com/scripting (dem Link „Windows Script“ folgen)
JAVA
http://java.sun.com/
http://java.sun.com/downloads.html (JSE)
http://java.sun.com/j2se/1.4/download.html
Apache
http://www.apache.org/
http://www.apache.org/dist/httpd/binaries/win32/
PWS
enthalten in NT 4.0 Option Pack für Windows 95
enthalten in CD für Windows 98
http://www.microsoft.com/ntserver/nts/downloads/recommended/NT4OptPk/win95.asp
IIS 
(windows NT/2000)
http://www.microsoft.com
Tomcat
http://jakarta.apache.org/tomcat/
JBuilder
http://www.borland.com/jbuilder/
http://www.borland.com/products/downloads/download_jbuilder.html
EasyPHP
http://www.easyphp.org/
http://www.easyphp.org/telechargements.php3

8.1.3. EasyPHP

Diese Anwendung ist sehr praktisch, da sie in einem einzigen Paket Folgendes vereint:

  • den Apache-Webserver (1.3.x)
  • die Sprache PHP (4.x)
  • das SGBD MySQL (3.23.x)
  • ein Verwaltungstool für MySQL: PhpMyAdmin

Die Installationsanwendung sieht wie folgt aus:

Image

Die Installation von EasyPHP verläuft problemlos, und im Dateisystem wird eine Verzeichnisstruktur angelegt:

Image

easyphp.exe
die ausführbare Datei der Anwendung
apache
die Verzeichnisstruktur des Apache-Servers
mysql
die Verzeichnisstruktur von SGBD MySQL
phpmyadmin
Verzeichnisstruktur der Anwendung phpMyAdmin
php
Verzeichnisstruktur von PHP
www
Stammverzeichnis der vom Apache-Server bereitgestellten Webseiten von EasyPHP
cgi-bin
Verzeichnisbaum, in dem Skripte vom Typ CGI für den Apache-Server abgelegt werden können

Der Hauptvorteil von EasyPHP besteht darin, dass die Anwendung vorkonfiguriert geliefert wird. Somit sind Apache, PHP und MySQL bereits für die Zusammenarbeit konfiguriert. Wenn man EasyPhp über die Verknüpfung im Programmmenü startet, erscheint unten rechts auf dem Bildschirm ein Symbol.

Das „E“ mit dem roten Punkt sollte blinken, wenn der Webserver Apache und die Datenbank MySQL betriebsbereit sind. Wenn man mit der rechten Maustaste darauf klickt, werden folgende Menüoptionen angezeigt:

Image

Mit der Option Administration können Einstellungen vorgenommen und Funktionstests durchgeführt werden:

Image

8.1.3.1. Verwaltung PHP

Über die Schaltfläche „PHP-Infos“ können Sie die ordnungsgemäße Funktion des Apache-PHP-Paares überprüfen: Es sollte eine Informationsseite mit der Bezeichnung PHP erscheinen:

Image

Die Schaltfläche „Erweiterungen“ zeigt eine Liste der für PHP installierten Erweiterungen an. Dabei handelt es sich eigentlich um Funktionsbibliotheken.

Image

Der obige Bildschirm zeigt beispielsweise, dass die für die Nutzung der Datenbank „MySQL“ erforderlichen Funktionen vorhanden sind.

Über die Schaltfläche „Einstellungen“ werden die login/motdepasse des Datenbankadministrators MySQL angezeigt.

Image

Die Verwendung der Datenbank MySQL würde den Rahmen dieser kurzen Einführung sprengen, aber es ist hier klar, dass für den Datenbankadministrator ein Passwort festgelegt werden müsste.

8.1.3.2. Apache-Verwaltung

Ebenfalls auf der Verwaltungsseite von EasyPHP können Sie über den Link „Ihre Aliase“ Aliase definieren, die einem Verzeichnis zugeordnet sind. Auf diese Weise können Webseiten an anderen Orten als im Verzeichnis „www“ der Verzeichnisstruktur von easyPhp abgelegt werden.

Image

Wenn man auf der oben genannten Seite die folgenden Angaben macht:

Image

und die Schaltfläche valider verwendet wird, werden die folgenden Zeilen zur Datei <easyphp>\apache\conf\httpd.conf hinzugefügt:

    Alias /st/ "e:/data/serge/web/"

    <Directory "e:/data/serge/web">
        Options FollowSymLinks Indexes
        AllowOverride None
        Order deny,allow
        allow from 127.0.0.1
        deny from all
    </Directory>

<easyphp> bezeichnet das Installationsverzeichnis von EasyPHP. httpd.conf ist die Konfigurationsdatei des Apache-Servers. Man kann dies also auch erreichen, indem man diese Datei direkt bearbeitet. Eine Änderung an der Datei httpd.conf wird normalerweise sofort von Apache übernommen. Sollte dies nicht der Fall sein, müsste man den Server beenden und anschließend neu starten, jeweils über das EasyPHP-Symbol:

Image

Um unser Beispiel abzuschließen, können wir nun Webseiten im Verzeichnisbaum e:\data\serge\web ablegen:

C:\winnt\system32>dir e:\data\serge\web\html\balises.htm

14/07/2002  17:02                3 767 balises.htm

und diese Seite über den Alias „st“ aufrufen:

Image

In diesem Beispiel wurde der Apache-Server so konfiguriert, dass er auf Port 81 läuft. Sein Standardport ist 80. Dies wird durch die folgende Zeile in der bereits erwähnten Datei httpd.conf gesteuert:

Port 81

8.1.3.3. Die Apache-Konfigurationsdatei htpd.conf

Wenn man Apache etwas genauer konfigurieren möchte, muss man seine Konfigurationsdatei httpd.conf, die sich hier im Ordner <easyphp>\apache\conf befindet, „von Hand“ bearbeiten:

Image

Hier sind einige wichtige Punkte aus dieser Konfigurationsdatei:

ligne(s)
Rolle
ServerRoot "D:/Program Files/Apache Group/Apache"
Gibt den Ordner an, in dem sich die Apache-Verzeichnisstruktur befindet
Port 80
gibt an, auf welchem Port der Webserver arbeiten wird. Standardmäßig ist dies Port 80. Durch Ändern dieser Zeile kann der Webserver auf einem anderen Port betrieben werden
ServerAdmin root@istia.univ-angers.fr
die E-Mail-Adresse des Apache-Serveradministrators
ServerName stahe.istia.uang
der Name des Rechners, auf dem der Apache-Server „läuft“
ServerRoot "E:/Program Files/EasyPHP/apache"
das Installationsverzeichnis des Apache-Servers. Wenn in der Konfigurationsdatei relative Dateinamen vorkommen, beziehen sie sich auf diesen Ordner.
DocumentRoot "E:/Program Files/EasyPHP/www"
Das Stammverzeichnis der vom Server bereitgestellten Webseiten. Hier entspricht die URL http://machine/rep1/fic1.html der Datei E:\Program Files\EasyPHP\www\rep1\fic1.html
<Directory "E:/Program Files/EasyPHP/www">
legt die Eigenschaften des vorherigen Ordners fest
ErrorLog logs/error.log
Log-Ordner, also eigentlich <ServerRoot>\logs\error.log: E:\Program Files\EasyPHP\apache\logs\error.log. Diese Datei sollten Sie überprüfen, wenn Sie feststellen, dass der Apache-Server nicht funktioniert.
    ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/"
E:\Program Files\EasyPHP\cgi-bin ist das Stammverzeichnis des Verzeichnisbaums, in dem Skripte mit dem Namen CGI abgelegt werden können. Somit lautet die URL des Skripts CGI E:\http://machine/cgi-bin/rep1/script1.pl: URL E:\Program Files\EasyPHP\cgi-bin\rep1\script1.pl.
<Directory "E:/Program Files/EasyPHP/cgi-bin/">
legt die Eigenschaften des oben genannten Ordners fest
LoadModule php4_module "E:/Program
 Files/EasyPHP/php/php4apache.dll"
AddModule mod_php4.c
Ladezeilen für die Module, die es Apache ermöglichen, mit PHP4 zu arbeiten.
    AddType application/x-httpd-php
 .phtml .pwml .php3 
.php4 .php .php2 .inc
Legt die Dateiendungen fest, die als von PHP zu verarbeitende Dateien gelten sollen

8.1.3.4. Verwaltung von MySQL mit PhpMyAdmin

Auf der Verwaltungsseite von EasyPhp klicken Sie auf die Schaltfläche PhpMyAdmin:

Image

Über die Dropdown-Liste unter Accueil können die
.
Die Zahl in Klammern gibt die Anzahl der Tabellen an. Wenn man
eine Datenbank auswählt, werden deren Tabellen angezeigt:

Die Webseite bietet eine Reihe von Funktionen für die Datenbank:

Image

Wenn man auf den Link Afficher von user klickt:

Image

Hier gibt es nur einen einzigen Benutzer: root, der Administrator von MySQL. Über den Link Modifier könnte man sein Passwort ändern, das derzeit leer ist, was für einen Administrator jedoch nicht empfehlenswert ist.

Wir werden nicht weiter auf PhpMyAdmin eingehen, da es sich um eine umfangreiche Software handelt, deren Beschreibung mehrere Seiten füllen würde.

8.1.4. PHP

Wir haben gesehen, wie man PHP über die Anwendung EasyPhp erhält. Um PHP direkt zu erhalten, ruft man die Website http://www.php.net auf.

PHP ist nicht nur im Web einsetzbar. Man kann es auch als Skriptsprache unter Windows verwenden. Erstellen Sie das folgende Skript und speichern Sie es unter dem Namen date.php:

<?
   // PHP-Skript, das die Uhrzeit anzeigt
  $maintenant=date("j/m/y, H:i:s",time());
  echo "Nous sommes le $maintenant";
?>

Wechseln Sie in einem Fenster mit der Nummer DOS in das Verzeichnis von date.php und führen Sie es aus:

E:\data\serge\php\essais>"e:\program files\easyphp\php\php.exe" date.php
X-Powered-By: PHP/4.2.0
Content-type: text/html

Nous sommes le 18/07/02, 09:31:01

8.1.5. PERL

Es ist empfehlenswert, dass der Internet Explorer bereits installiert ist. Ist dies der Fall, konfiguriert Active Perl ihn so, dass er PERL-Skripte in HTML-Seiten akzeptiert, die dann von IE selbst auf der Client-Seite ausgeführt werden. Die Website von Active Perl ist unter URL http://www.activestate.comA zu finden. Nach der Installation wird PERL in einem Verzeichnis installiert, das wir <perl> nennen. Es enthält die folgende Verzeichnisstruktur:

DEISL1   ISU        32 403  23/06/00  17:16 DeIsL1.isu
BIN            <REP>        23/06/00  17:15 bin
LIB            <REP>        23/06/00  17:15 lib
HTML           <REP>        23/06/00  17:15 html
EG             <REP>        23/06/00  17:15 eg
SITE           <REP>        23/06/00  17:15 site
HTMLHELP       <REP>        28/06/00  18:37 htmlhelp

Die ausführbare Datei perl.exe befindet sich in <perl>\bin. Perl ist eine Skriptsprache, die unter Windows und Unix läuft. Sie wird außerdem bei der Programmierung von WEB verwendet. Schreiben wir ein erstes Skript:

# PERL-Skript, das die Uhrzeit anzeigt

# Module
use strict;

# Programm
my ($secondes,$minutes,$heure)=localtime(time);
print "Il est $heure:$minutes:$secondes\n";

Speichern Sie dieses Skript in einer Datei mit dem Namen heure.pl. Öffnen Sie ein Fenster mit dem Namen DOS, wechseln Sie in das Verzeichnis des oben genannten Skripts und führen Sie es aus:

E:\data\serge\Perl\Essais>e:\perl\bin\perl.exe heure.pl
Il est 9:34:21

8.1.6. VBScript, JavaScript, PerlScript

Diese Sprachen sind Skriptsprachen für Windows. Sie können in verschiedenen Containern wie

  • Windows Scripting Host für den direkten Einsatz unter Windows, insbesondere zum Schreiben von Skripten zur Systemadministration
  • Internet Explorer. Dort wird es in HTML-Seiten verwendet, denen es eine gewisse Interaktivität verleiht, die mit der Sprache HTML allein nicht zu erreichen wäre.
  • Internet Information Server (IIS), dem Webserver von Microsoft unter NT/2000, und dessen Entsprechung, dem Personal Web Server (PWS), unter Win9x. In diesem Fall wird VBScript für die serverseitige Programmierung verwendet, eine Technologie, die von Microsoft als ASP (Active Server Pages) bezeichnet wird.

Die Installationsdatei URL wird unter http://msdn.microsoft.com/scripting heruntergeladen, und man folgt den Links zu „Windows Script“. Installiert werden:

  • der Windows Scripting Host, ein Container, der die Verwendung verschiedener Skriptsprachen wie VBScript und JavaScript, aber auch anderer Sprachen wie PerlScript ermöglicht, das mit Active Perl mitgeliefert wird.
  • ein VBscript-Interpreter
  • ein JavaScript-Interpreter

Führen wir einige kurze Tests durch. Erstellen wir das folgende Programm „vbscript“:

' eine Klasse
class personne
  Dim nom
  Dim age
End class

' Erstellung eines Personenobjekts
Set p1=new personne
With p1
  .nom="dupont"
  .age=18
End With

' Anzeige der Eigenschaften der Person p1
With p1
  wscript.echo "nom=" & .nom
  wscript.echo "age=" & .age
End With

Dieses Programm verwendet Objekte. Nennen wir es objets.vbs (die Endung „vbs“ steht für eine VBScript-Datei). Wechseln wir in das Verzeichnis, in dem es sich befindet, und führen wir es aus:

E:\data\serge\windowsScripting\vbscript\poly\objets>cscript objets.vbs
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

nom=dupont
age=18

Nun erstellen wir das folgende JavaScript-Programm, das Arrays verwendet:

// Array in einer Variante
// leeres Array
tableau=new Array();
affiche(tableau);
// Array wächst dynamisch
for(i=0;i<3;i++){
  tableau.push(i*10);
}
// Anzeige des Arrays
affiche(tableau);
// nochmals
for(i=3;i<6;i++){
  tableau.push(i*10);
}
affiche(tableau);

// mehrdimensionale Tabellen
WScript.echo("-----------------------------");

tableau2=new Array();
for(i=0;i<3;i++){
  tableau2.push(new Array());
  for(j=0;j<4;j++){
    tableau2[i].push(i*10+j);
  }//for j
}// for i
affiche2(tableau2);

// Ende
WScript.quit(0);

// ---------------------------------------------------------
function affiche(tableau){
  // Tabellenanzeige
  for(i=0;i<tableau.length;i++){
    WScript.echo("tableau[" + i + "]=" + tableau[i]);
  }//für
}//Funktion

// ---------------------------------------------------------
function affiche2(tableau){
   // Tabellenanzeige
  for(i=0;i<tableau.length;i++){
    for(j=0;j<tableau[i].length;j++){
      WScript.echo("tableau[" + i + "," + j + "]=" + tableau[i][j]);
    }// für j
  }//für i
}//Funktion

Dieses Programm verwendet Arrays. Nennen wir es tableaux.js (die Endung „js“ steht für eine JavaScript-Datei). Wechseln wir in das Verzeichnis, in dem es sich befindet, und führen wir es aus:

E:\data\serge\windowsScripting\javascript\poly\tableaux>cscript tableaux.js
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.

tableau[0]=0
tableau[1]=10
tableau[2]=20
tableau[0]=0
tableau[1]=10
tableau[2]=20
tableau[3]=30
tableau[4]=40
tableau[5]=50
-----------------------------
tableau[0,0]=0
tableau[0,1]=1
tableau[0,2]=2
tableau[0,3]=3
tableau[1,0]=10
tableau[1,1]=11
tableau[1,2]=12
tableau[1,3]=13
tableau[2,0]=20
tableau[2,1]=21
tableau[2,2]=22
tableau[2,3]=23

Zum Abschluss noch ein letztes Beispiel in Perlscript. Um auf Perlscript zugreifen zu können, muss Active Perl installiert sein.

<job id="PERL1">
  <script language="PerlScript">
       # klassisches Perl
    %dico=("maurice"=>"juliette","philippe"=>"marianne");
    @cles= keys %dico;
    for ($i=0;$i<=$#Schlüssel;$i++){
        $cle=$cles[$i];
      $valeur=$dico{$cle};
        $WScript->echo ("clé=".$cle.", valeur=".$valeur);
    }
     # Perl-Skript unter Verwendung von Windows-Script-Objekten
    $dico=$WScript->CreateObject("Scripting.Dictionary");
    $dico->add("maurice","juliette");
    $dico->add("philippe","marianne");
    $WScript->echo($dico->item("maurice"));
    $WScript->echo($dico->item("philippe"));    
  </script>
</job>

Dieses Programm veranschaulicht die Erstellung und Verwendung von zwei Wörterbüchern: eines im klassischen Perl-Stil, das andere mit dem „Scripting Dictionary“-Objekt von Windows Script. Speichern wir diesen Code in der Datei dico.wsf (wsf ist die Dateiendung für Windows-Script-Dateien). Wechseln wir in den Ordner dieses Programms und führen wir es aus:

E:\data\serge\windowsScripting\perlscript\essais>cscript dico.wsf
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. Tous droits réservés.

clé=philippe, valeur=marianne
clé=maurice, valeur=juliette
juliette
marianne

Perlscript kann auf die Objekte des Containers zugreifen, in dem es ausgeführt wird. In diesem Fall handelte es sich um Objekte des Windows-Script-Containers. Im Kontext der Webprogrammierung können die Skripte VBscript, JavaScript- und Perlscript-Skripte entweder im Browser IE oder auf einem Server PWS bzw. IIS ausgeführt werden. Ist das Skript etwas komplexer, kann es sinnvoll sein, es außerhalb des Webkontexts im Windows-Script-Container zu testen, wie zuvor beschrieben. Auf diese Weise lassen sich jedoch nur die Funktionen des Skripts testen, die keine browser- oder servereigenen Objekte verwenden. Trotz dieser Einschränkung bleibt diese Möglichkeit interessant, da es in der Regel recht umständlich ist, Skripte zu debuggen, die auf Webservern oder in Browsern ausgeführt werden.

8.1.7. JAVA

Java ist unter der URL verfügbar: http://www.sun.com und wird in einem Verzeichnisbaum installiert, den wir <java> nennen und der folgende Elemente enthält:

22/05/2002  05:51       <DIR>          .
22/05/2002  05:51       <DIR>          ..
22/05/2002  05:51       <DIR>          bin
22/05/2002  05:51       <DIR>          jre
07/02/2002  12:52                8 277 README.txt
07/02/2002  12:52               13 853 LICENSE
07/02/2002  12:52                4 516 COPYRIGHT
07/02/2002  12:52               15 290 readme.html
22/05/2002  05:51       <DIR>          lib
22/05/2002  05:51       <DIR>          include
22/05/2002  05:51       <DIR>          demo
07/02/2002  12:52           10 377 848 src.zip
11/02/2002  12:55       <DIR>          docs

Im Verzeichnis „bin“ befinden sich javac.exe, der Java-Compiler, und java.exe, die Java-Virtual-Machine. Folgende Tests können durchgeführt werden:

  1. Schreiben Sie das folgende Skript:
//Java-Programm zur Anzeige der Uhrzeit

import java.io.*;
import java.util.*;

public class heure{
  public static void main(String arg[]){
     // Datum und Uhrzeit abrufen
     Date maintenant=new Date();
      // Anzeige
     System.out.println("Il est "+maintenant.getHours()+
        ":"+maintenant.getMinutes()+":"+maintenant.getSeconds());
  }//main
}//Klasse
  1. Speichern Sie dieses Programm unter dem Namen heure.java. Öffnen Sie ein Fenster mit dem Namen DOS. Wechseln Sie in das Verzeichnis der Datei heure.java und kompilieren Sie sie:
D:\data\java\essais>c:\jdk1.3\bin\javac heure.java
Note: heure.java uses or overrides a deprecated API.
Note: Recompile with -deprecation for details.

In dem obigen Befehl muss c:\jdk1.3\bin\javac durch den genauen Pfad zum Compiler javac.exe ersetzt werden. Im selben Verzeichnis wie heure.java muss sich eine Datei namens heure.class befinden. Dabei handelt es sich um das Programm, das nun von der virtuellen Maschine java.exe ausgeführt wird.

  1. Führen Sie das Programm aus:
D:\data\java\essais>c:\jdk1.3\bin\java heure
Il est 10:44:2

8.1.8. Apache-Server

Wir haben gesehen, dass man den Apache-Server mit der Anwendung EasyPhp erhalten kann. Um ihn direkt zu beziehen, rufen wir die Apache-Website auf: http://www.apache.org. Bei der Installation wird ein Verzeichnisbaum erstellt, in dem sich alle für den Server erforderlichen Dateien befinden. Nennen wir dieses Verzeichnis <apache>. Es enthält einen Verzeichnisbaum, der in etwa wie folgt aussieht:

UNINST   ISU       118 805  23/06/00  17:09 Uninst.isu
HTDOCS         <REP>        23/06/00  17:09 htdocs
APACHE~1 DLL       299 008  25/02/00  21:11 ApacheCore.dll
ANNOUN~1             3 000  23/02/00  16:51 Announcement
ABOUT_~1            13 197  31/03/99  18:42 ABOUT_APACHE
APACHE   EXE        20 480  25/02/00  21:04 Apache.exe
KEYS                36 437  20/08/99  11:57 KEYS
LICENSE              2 907  01/01/99  13:04 LICENSE
MAKEFI~1 TMP        27 370  11/01/00  13:47 Makefile.tmpl
README               2 109  01/04/98   6:59 README
README   NT          3 223  19/03/99   9:55 README.NT
WARNIN~1 TXT           339  21/09/98  13:09 WARNING-NT.TXT
BIN            <REP>        23/06/00  17:09 bin
MODULES        <REP>        23/06/00  17:09 modules
ICONS          <REP>        23/06/00  17:09 icons
LOGS           <REP>        23/06/00  17:09 logs
CONF           <REP>        23/06/00  17:09 conf
CGI-BIN        <REP>        23/06/00  17:09 cgi-bin
PROXY          <REP>        23/06/00  17:09 proxy
INSTALL  LOG         3 779  23/06/00  17:09 install.log
conf
Ordner mit den Apache-Konfigurationsdateien
logs
Ordner mit den Apache-Protokolldateien (Überwachung)
bin
Die ausführbaren Dateien von Apache

8.1.8.1. Configuration

Im Ordner <Apache>\conf befinden sich die folgenden Dateien: httpd.conf, srm.conf, access.conf. In den neuesten Apache-Versionen wurden die drei Dateien in httpd.conf zusammengefasst. Wir haben bereits die wichtigsten Punkte dieser Konfigurationsdatei vorgestellt. In den folgenden Beispielen diente die Apache-Version von EasyPhp als Testgrundlage und somit auch deren Konfigurationsdatei. Darin ist DocumentRoot, das den Stammordner der Webseiten angibt, e:\program files\easyphp\www.

Erstellen Sie zum Testen die Datei „intro.php“ mit der folgenden einzigen Zeile:

<? phpinfo() ?>

und legen Sie sie im Stammverzeichnis des Apache-Servers ab (DocumentRoot oben). Rufen Sie die Seite URL unter http://localhost/intro.php auf. Es sollte eine Liste mit Informationen zu php angezeigt werden:

Image

Das folgende Skript PHP zeigt die Uhrzeit an. Wir sind ihm bereits begegnet:

<?php
   // Zeit: Anzahl der Millisekunden seit dem 01.01.1970
   // „Anzeigeformat für Datum und Uhrzeit“
   // d: Tag, zweistellig
   // m: zweistelliger Monat
   // y: zweistelliges Jahr
   // H: Stunde 0,23
   // i: Minuten
   // s: Sekunden
  print "Nous sommes le " . date("d/m/y H:i:s",time());
?>

Legen wir diese Textdatei im Stammverzeichnis des Apache-Servers ab (DocumentRoot) und nennen wir sie date.php. Rufen wir mit einem Browser die Seite URL unter http://localhost/date.php auf. Wir erhalten folgende Seite:

Image

Er wird mithilfe einer Zeile der Form: ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/" aus der Datei <apache>\conf\httpd.conf erstellt. Die Syntax lautet ScriptAlias /cgi-bin/ "<cgi-bin>", wobei <cgi-bin> der Ordner ist, in dem CGI-Skripte abgelegt werden können. CGI (Common Gateway Interface) ist ein Standard für die Kommunikation zwischen dem Server WEB und Anwendungen. Ein Client fordert vom Webserver eine dynamische Seite an, c.a.d, d. h. eine Seite, die von einem Programm generiert wird. Der Server WEB muss daher ein Programm auffordern, die Seite zu generieren. CGI definiert die Kommunikation zwischen dem Server und dem Programm, insbesondere die Art und Weise, wie Informationen zwischen diesen beiden Einheiten übertragen werden.

Ändern Sie bei Bedarf die Zeile ScriptAlias /cgi-bin/ „<cgi-bin>“ und starten Sie den Apache-Server neu. Führen Sie anschließend folgenden Test durch:

  1. Schreiben Sie das Skript:
#!c:\perl\bin\perl.exe

# Skript PERL zur Anzeige der Uhrzeit

# Module
use strict;

# Programm
my ($secondes,$minutes,$heure)=localtime(time);
print <<FINHTML
Content-Type: text/html

<html>
 <head>
  <title>heure</title>
 </head>
 <body>
  <h1>Il est $heure:$minutes:$secondes</h1>
 </body>
FINHTML
;
  1. Legen Sie dieses Skript in <cgi-bin>\heure.pl ab, wobei <cgi-bin> der Ordner ist, in dem Skripte vom Typ CGI abgelegt werden können (siehe httpd.conf). Die erste Zeile #!c:\perl\bin\perl.exe gibt den Pfad zur ausführbaren Datei perl.exe an. Ändern Sie diesen bei Bedarf.
  2. Starten Sie Apache, falls dies noch nicht geschehen ist
  3. Rufen Sie mit einem Browser die Seite URL unter http://localhost/cgi-bin/heure.pl auf. Es wird folgende Seite angezeigt:

Image

8.1.9. Der Server PWS

8.1.9.1. Installation

Der Server PWS (Personal Web Server) ist eine persönliche Version des Servers IIS (Internet Information Server) von Microsoft. Letzterer ist auf den Systemen NT und 2000 verfügbar. Auf Win9x-Rechnern ist PWS normalerweise im Internet Explorer-Installationspaket enthalten. Er wird jedoch nicht standardmäßig installiert. Man muss eine benutzerdefinierte Installation von IE durchführen und die Installation von PWS anfordern. Es ist außerdem im NT 4.0 Option Pack für Windows 95 enthalten.

8.1.9.2. Erste Tests

Der Stammordner der Webseiten des Servers PWS lautet „Laufwerk:\inetpub\wwwroot“, wobei „Laufwerk“ das Laufwerk ist, auf dem Sie PWS installiert haben. Im Folgenden gehen wir davon aus, dass es sich bei diesem Laufwerk um D handelt. Somit entspricht die URL http://machine/rep1/page1.html der Datei d:\inetpub\wwwroot\rep1\page1.html. Der Server PWS interpretiert jede Datei mit der Endung .asp (Active Server Pages) als Skript, das er ausführen muss, um eine Seite HTML zu erzeugen.

PWS läuft standardmäßig auf Port 80. Der Apache-Webserver ebenfalls... Sie müssen daher Apache beenden, um mit PWS arbeiten zu können, wenn Sie beide Server haben. Die andere Lösung besteht darin, Apache so zu konfigurieren, dass er auf einem anderen Port läuft. Dazu ersetzt man in der Apache-Konfigurationsdatei httpd.conf die Zeile „Port 80“ durch „Port 81“. Apache läuft nun auf Port 81 und kann gleichzeitig mit PWS verwendet werden. Wenn PWS gestartet wurde und man die Seite http://localhost aufruft, erhält man eine Seite, die in etwa wie folgt aussieht:

Image

  1. Nachfolgend finden Sie eine .reg-Datei zur Änderung der Registrierungsdatenbank. Doppelklicken Sie auf diese Datei, um die Registrierung zu ändern. Hier befindet sich die benötigte dll in d:\php4 zusammen mit der PHP-Ausführungsdatei. Nehmen Sie bei Bedarf Änderungen vor. Die Backslashes (\) im Pfad zur DLL müssen verdoppelt werden.
REGEDIT4

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w3svc\parameters\Script Map]
".php"="d:\\php4\\php4isapi.dll"
  1. Starten Sie den Rechner neu, damit die Änderung in der Registrierungsdatenbank übernommen wird.
  1. Erstellen Sie einen PHP-Ordner in d:\inetpub\wwwroot, dem Stammverzeichnis des Servers PWS. Aktivieren Sie anschließend PWS und wechseln Sie zur Registerkarte „Erweitert“. Klicken Sie auf die Schaltfläche „Hinzufügen“, um einen virtuellen Ordner zu erstellen:
Répertoire/Parcourir : d:\inetpub\wwwroot\php
Alias : php
Cocher la case exécuter.
  1. Bestätigen Sie alles und starten Sie PWS neu. Fügen Sie in d:\inetpub\wwwroot\php die Datei intro.php ein, die ausschließlich die folgende Zeile enthält:
<? phpinfo() ?>
  1. Fordern Sie vom Server PWS die Datei URL „http://localhost/php/intro.php“ an. Es sollte die Liste der PHP-Informationen angezeigt werden, die bereits mit Apache dargestellt wurden.

8.1.10. Tomcat: Java-Servlets und JSP-Seiten (Java Server Pages)

Tomcat ist ein Webserver, mit dem sich HTML-Seiten mithilfe von Servlets (vom Webserver ausgeführte Java-Programme) oder JSP-Seiten (Java Server Pages) erstellen lassen, bei denen Java-Code und HTML-Code miteinander kombiniert werden. Dies entspricht den ASP-Seiten (Active Server Pages) des Microsoft-Servers IIS/PWS, bei denen VBScript-Code oder JavaScript mit HTML-Code vermischt wird.

8.1.10.1. Installation

Tomcat ist unter der Adresse URL verfügbar: http://jakarta.apache.org. Man lädt eine .exe-Installationsdatei herunter. Wenn man dieses Programm startet, gibt es zunächst an, welche Java-Version es verwenden wird. Tatsächlich benötigt Tomcat eine Java-Version, um sich zu installieren und anschließend die Java-Servlets zu kompilieren und auszuführen. Sie müssen daher vor der Installation von Tomcat eine Java-Version installiert haben. Es wird die aktuellste Version empfohlen. Die Installation erstellt einen Ordnerbaum <tomcat>:

Image

Die Installation besteht lediglich darin, dieses Archiv in ein Verzeichnis zu entpacken. Wählen Sie ein Verzeichnis, dessen Pfad ausschließlich Namen ohne Leerzeichen enthält (also beispielsweise nicht „Program Files“), da es einen Fehler im Installationsprozess von Tomcat gibt. Verwenden Sie beispielsweise C:\tomcat oder D:\tomcat. Nennen wir dieses Verzeichnis <tomcat>. Darin befindet sich ein Ordner namens jakarta-tomcat, der wiederum die folgende Verzeichnisstruktur enthält:

LOGS           <REP>        15/11/00   9:04 logs
LICENSE              2 876  18/04/00  15:56 LICENSE
CONF           <REP>        15/11/00   8:53 conf
DOC            <REP>        15/11/00   8:53 doc
LIB            <REP>        15/11/00   8:53 lib
SRC            <REP>        15/11/00   8:53 src
WEBAPPS        <REP>        15/11/00   8:53 webapps
BIN            <REP>        15/11/00   8:53 bin
WORK           <REP>        15/11/00   9:04 work

8.1.10.2. Starten/Beenden des Tomcat-Webservers

Tomcat ist ein Webserver, genau wie Apache oder PWS. Um ihn zu starten, stehen im Programmmenü folgende Verknüpfungen zur Verfügung:

Start Tomcat
zum Starten von Tomcat
Stop Tomcat
zum Beenden

Beim Starten von Tomcat wird ein DOS-Fenster mit folgendem Inhalt angezeigt:

Image

Dieses DOS-Fenster kann minimiert werden. Es bleibt so lange sichtbar, wie Tomcat aktiv ist. Anschließend können die ersten Tests durchgeführt werden. Der Tomcat-Webserver läuft auf Port 8080. Sobald Tomcat gestartet ist, öffnen Sie einen Webbrowser und rufen Sie die Adresse URL http://localhost:8080 auf. Sie sollten die folgende Seite sehen:

Image

Folgen Sie dem Link „Servlet Examples“:

Image

Klicken Sie auf den Link Execute von RequestParameters und anschließend auf den Link von Source. So erhalten Sie einen ersten Einblick in die Funktionsweise eines Java-Servlets. Das Gleiche können Sie mit den Links auf den Seiten JSP tun.

Um Tomcat zu beenden, verwenden Sie den Link „Stop Tomcat“ im Programmmenü.

8.1.11. JBuilder

JBuilder ist eine Entwicklungsumgebung für Java-Anwendungen. Um Java-Servlets zu erstellen, bei denen keine grafischen Benutzeroberflächen vorhanden sind, ist eine solche Umgebung nicht unbedingt erforderlich. Ein Texteditor und ein JDK reichen aus. Lediglich JBuilder bietet gegenüber der vorherigen Methode einige Vorteile:

  • Einfache Fehlersuche: Der Compiler zeigt fehlerhafte Zeilen in einem Programm an, und es ist einfach, die entsprechende Stelle zu finden
  • Code-Vorschläge: Bei der Verwendung eines Java-Objekts zeigt JBuilder inline eine Liste der Eigenschaften und Methoden dieses Objekts an. Das ist sehr praktisch, da die meisten Java-Objekte sehr viele Eigenschaften und Methoden haben, die man sich nur schwer merken kann.

JBuilder ist auf der Website http://www.borland.com/jbuilder zu finden. Um die Software zu erhalten, muss ein Formular ausgefüllt werden. Ein Aktivierungsschlüssel wird per E-Mail zugesandt. Zur Installation von JBuilder 7 wurde beispielsweise wie folgt vorgegangen:

  • Es wurden drei ZIP-Dateien heruntergeladen: für die Anwendung, für die Dokumentation und für die Beispiele. Für jede dieser ZIP-Dateien gibt es einen separaten Link auf der Website von JBuilder.
  • Zuerst wurde die Anwendung installiert, dann die Dokumentation und schließlich die Beispiele
  • Beim ersten Start der Anwendung wird ein Aktivierungsschlüssel abgefragt: Dies ist der Schlüssel, der Ihnen per E-Mail zugesandt wurde. In Version 7 besteht dieser Schlüssel tatsächlich aus dem gesamten Inhalt einer Textdatei, die Sie beispielsweise im Installationsordner von JB7 ablegen können. Wenn der Schlüssel abgefragt wird, wählen Sie einfach die betreffende Datei aus. Sobald dies geschehen ist, wird der Schlüssel nicht mehr abgefragt.

Es sind einige nützliche Konfigurationen vorzunehmen, wenn man JBuilder zum Erstellen von Java-Servlets verwenden möchte. Die sogenannte „Jbuilder Personal“-Version ist nämlich eine abgespeckte Version, die insbesondere nicht alle Klassen enthält, die für die Webentwicklung in Java erforderlich sind. Man kann dafür sorgen, dass JBuilder die von Tomcat bereitgestellten Klassenbibliotheken verwendet. Dazu geht man wie folgt vor:

  • Starten Sie JBuilder

Image

  • die Option „Tools/Configure JDKs“ aktivieren

Image

Im obigen Bereich „JDK Settings“ steht normalerweise im Feld „Name“ ein Eintrag wie „JDK 1.3.1“. Wenn Sie eine neuere Version von JDK haben, verwenden Sie die Schaltfläche „Change“, um das Installationsverzeichnis dieser Version anzugeben. Oben wurde das Verzeichnis E:\Program Files\jdk14 angegeben, in dem ein JDK 1.4 installiert war. Von nun an wird JBuilder dieses JDK für seine Kompilierungen und Ausführungen verwenden. Im Bereich (Class, Source, Documentation) finden Sie die Liste aller Klassenbibliotheken, die von JBuilder durchsucht werden, in diesem Fall die Klassen von JDK 1.4. Die darin enthaltenen Klassen reichen für die Webentwicklung in Java nicht aus. Um weitere Klassenbibliotheken hinzuzufügen, verwendet man die Schaltfläche „Add“ und wählt die zusätzlichen .jar-Dateien aus, die man verwenden möchte. Die .jar-Dateien sind Klassenbibliotheken. Tomcat 4.x enthält bereits alle für die Webentwicklung erforderlichen Klassenbibliotheken. Diese befinden sich unter <tomcat>\common\lib, wobei <tomcat> das Installationsverzeichnis von Tomcat ist:

Image

Mit der Schaltfläche „Add“ fügen wir diese Bibliotheken nacheinander zur Liste der von JBuilder durchsuchten Bibliotheken hinzu:

Image

Ab sofort können Java-Programme gemäß dem Standard J2EE kompiliert werden, insbesondere Java-Servlets. JBuilder dient lediglich der Kompilierung; die Ausführung erfolgt anschließend durch Tomcat gemäß den im Kurs erläuterten Modalitäten.

8.2. Quellcode von Programmen

8.2.1. Der generische Client TCP

Viele Dienste, die zu Beginn des Internets entstanden sind, funktionieren nach dem zuvor behandelten Echo-Server-Modell: Der Austausch zwischen Client und Server erfolgt über den Austausch von Textzeilen. Wir werden einen generischen TCP-Client schreiben, der wie folgt gestartet wird: java cltTCPgenerique Server Port

Dieser Client TCP stellt eine Verbindung zum Port port des Servers serveur her. Anschließend erstellt er zwei Threads:

  1. einen Thread, der die über die Tastatur eingegebenen Befehle liest und an den Server sendet
  2. ein Thread, der die Antworten des Servers liest und auf dem Bildschirm anzeigt

Warum zwei Threads? Jeder TCP-IP-Dienst hat sein eigenes Protokoll, und manchmal treten folgende Situationen auf:

  • Der Client muss mehrere Textzeilen senden, bevor er eine Antwort erhält
  • Die Antwort eines Servers kann mehrere Textzeilen umfassen

Daher ist die Schleife „Senden einer einzelnen Zeile an den Server – Empfangen einer einzelnen Zeile vom Server“ nicht immer geeignet. Wir erstellen daher zwei voneinander getrennte Schleifen:

  • eine Schleife zum Einlesen der über die Tastatur eingegebenen Befehle, die an den Server gesendet werden sollen. Der Benutzer signalisiert das Ende der Befehle mit dem Schlüsselwort fin.
  • eine Schleife zum Empfangen und Anzeigen der Antworten des Servers. Dabei handelt es sich um eine Endlosschleife, die nur durch das Schließen der Netzwerkverbindung durch den Server oder durch den Benutzer über die Tastatur unterbrochen wird, indem dieser den Befehl fin eingibt.

Um diese beiden Schleifen voneinander zu trennen, benötigen wir zwei unabhängige Threads. Betrachten wir ein Ausführungsbeispiel, bei dem sich unser generischer TCP-Client mit einem Dienst namens SMTP (SendMail Transfer Protocol) verbindet. Dieser Dienst ist für die Weiterleitung von E-Mails an ihre Empfänger zuständig. Er läuft auf Port 25 und verwendet ein Dialogprotokoll, bei dem Textzeilen ausgetauscht werden.

Dos>java clientTCPgenerique istia.univ-angers.fr 25
Commandes :
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
help
<-- 502 5.3.0 Sendmail 8.11.6 -- HELP not implemented
mail from: machin@univ-angers.fr
<-- 250 2.1.0 machin@univ-angers.fr... Sender ok
rcpt to: serge.tahe@istia.univ-angers.fr
<-- 250 2.1.5 serge.tahe@istia.univ-angers.fr... Recipient ok
data
<-- 354 Enter mail, end with "." on a line by itself
Subject: test

ligne1
ligne2
ligne3
.
<-- 250 2.0.0 g4D6bks25951 Message accepted for delivery
quit
<-- 221 2.0.0 istia.univ-angers.fr closing connection
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]

Erläutern wir diesen Client-Server-Austausch:

  • Der Dienst SMTP sendet eine Begrüßungsnachricht, wenn sich ein Client bei ihm anmeldet:
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
  • Einige Dienste verfügen über den Befehl help, der Hinweise zu den mit dem Dienst verwendbaren Befehlen gibt. Hier ist dies nicht der Fall. Die im Beispiel verwendeten Befehle SMTP lauten wie folgt:
    • mail from: expéditeur, um die E-Mail-Adresse des Absenders der Nachricht anzugeben
    • rcpt to: destinataire, um die E-Mail-Adresse des Empfängers der Nachricht anzugeben. Bei mehreren Empfängern wird der Befehl „rcpt to:“ so oft wie nötig für jeden einzelnen Empfänger wiederholt.
    • data, das dem Server SMTP signalisiert, dass die Nachricht gesendet wird. Wie in der Antwort des Servers angegeben, handelt es sich dabei um eine Folge von Zeilen, die mit einer Zeile endet, die ausschließlich das Zeichen „.“ enthält. Eine Nachricht kann Kopfzeilen enthalten, die durch eine Leerzeile vom Nachrichtentext getrennt sind. In unserem Beispiel haben wir einen Betreff mit dem Schlüsselwort Subject: angegeben
  • Sobald die Nachricht gesendet wurde, kann man dem Server mit dem Befehl „quit“ mitteilen, dass man fertig ist. Der Server schließt daraufhin die Netzwerkverbindung. Der Lesethread kann dieses Ereignis erkennen und sich beenden.
  • Der Benutzer gibt dann „fin“ über die Tastatur ein, um auch den Thread zum Lesen der über die Tastatur eingegebenen Befehle zu beenden.

Wenn man die empfangene E-Mail überprüft, sieht man Folgendes (Outlook):

Image

Es ist zu beachten, dass der Dienst „SMTP“ nicht erkennen kann, ob ein Absender gültig ist oder nicht. Daher darf man dem Feld „from“ einer Nachricht niemals vertrauen. In diesem Fall existierte der Absender „machin@univ-angers.fr“ nicht.

Dieser generische TCP-Client ermöglicht es uns, das Kommunikationsprotokoll von Internetdiensten zu ermitteln und auf dieser Grundlage spezialisierte Klassen für Clients dieser Dienste zu erstellen. Sehen wir uns das Kommunikationsprotokoll des Dienstes POP (Post Office Protocol) an, mit dem man seine auf einem Server gespeicherten E-Mails abrufen kann. Er läuft auf Port 110.

Dos> java clientTCPgenerique istia.univ-angers.fr 110
Commandes :
<-- +OK Qpopper (version 4.0.3) at istia.univ-angers.fr starting.
help
<-- -ERR Unknown command: "help".
user st
<-- +OK Password required for st.
pass monpassword
<-- +OK st has 157 visible messages (0 hidden) in 11755927 octets.
list
<-- +OK 157 visible messages (11755927 octets)
<-- 1 892847
<-- 2 171661
...
<-- 156 2843
<-- 157 2796
<-- .
retr 157
<-- +OK 2796 octets
<-- Received: from lagaffe.univ-angers.fr (lagaffe.univ-angers.fr [193.49.144.1])
<--     by istia.univ-angers.fr (8.11.6/8.9.3) with ESMTP id g4D6wZs26600;
<--     Mon, 13 May 2002 08:58:35 +0200
<-- Received: from jaume ([193.49.146.242])
<--     by lagaffe.univ-angers.fr (8.11.1/8.11.2/GeO20000215) with SMTP id g4D6wSd37691;
<--     Mon, 13 May 2002 08:58:28 +0200 (CEST)
...
<-- ------------------------------------------------------------------------
<-- NOC-RENATER2                  Tl.  : 0800 77 47 95
<-- Fax : (+33) 01 40 78 64 00 ,  Email : noc-r2@cssi.renater.fr
<-- ------------------------------------------------------------------------
<--
<-- .
quit
<-- +OK Pop server at istia.univ-angers.fr signing off.
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]

Die wichtigsten Befehle lauten wie folgt:

  • user login, wobei man seinen Benutzernamen auf dem Rechner angibt, auf dem sich die E-Mails befinden
  • pass password, wobei man das zum vorherigen Login gehörende Passwort eingibt
  • list, um eine Liste der Nachrichten in Form von Nummer und Größe in Byte zu erhalten
  • retr i, um die Nachricht Nr. i zu lesen
  • quit, um die Verbindung zu beenden.

Sehen wir uns nun das Dialogprotokoll zwischen einem Client und einem Webserver an, der in der Regel auf Port 80 läuft:

Dos> java clientTCPgenerique istia.univ-angers.fr 80
Commandes :
GET /index.html HTTP/1.0

<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix)  (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
<--
<-- <head>
<-- <meta http-equiv="Content-Type"
<-- content="text/html; charset=iso-8859-1">
<-- <meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<-- <title>Bienvenue a l'ISTIA - Universite d'Angers</title>
<-- </head>
....
<-- face="Verdana"> - Dernire mise  jour le <b>10 janvier 2002</b></font></p>
<-- </body>
<-- </html>
<--
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]

Ein Webclient sendet seine Befehle nach folgendem Schema an den Server:

commande1
commande2
...
commanden
[ligne vide]

Erst nach Erhalt der leeren Zeile antwortet der Webserver. In diesem Beispiel haben wir nur einen Befehl verwendet:

GET /index.html HTTP/1.0

der den Server nach URL /index.html abfragt und angibt, dass er mit dem Protokoll HTTP Version 1.0 arbeitet. Die aktuellste Version dieses Protokolls ist 1.1. Das Beispiel zeigt, dass der Server mit dem Inhalt der Datei index.html geantwortet und anschließend die Verbindung geschlossen hat, da der Thread zum Lesen der Antworten beendet wurde. Vor dem Senden des Inhalts der Datei index.html hat der Webserver eine Reihe von Headern gesendet, die mit einer Leerzeile endeten:

<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix)  (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>

Die Zeile <html> ist die erste Zeile der Datei /index.html. Das Vorstehende wird als HTTP-Header (HyperText-Übertragungsprotokoll) bezeichnet. Wir werden hier nicht näher auf diese Header eingehen, aber man sollte bedenken, dass unser generischer Client Zugriff darauf gewährt, was zum Verständnis hilfreich sein kann. Die erste Zeile zum Beispiel:

<-- HTTP/1.1 200 OK

gibt an, dass der angesprochene Webserver das Protokoll HTTP/1.1 versteht und die angeforderte Datei erfolgreich gefunden hat (200 OK), wobei 200 ein HTTP-Antwortcode ist. Die Zeilen

<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html

teilen dem Client mit, dass er 11251 Bytes empfangen wird, die den Text HTML (HyperText Markup Language) darstellen, und dass die Verbindung nach Abschluss der Übertragung geschlossen wird.

Wir haben hier also einen sehr praktischen TCP-Client. Er kann zweifellos weniger als das offizielle Programm telnet, aber es war interessant, ihn selbst zu schreiben. Das Programm für den generischen TCP-Client lautet wie folgt:

// importierte Pakete
import java.io.*;
import java.net.*;

public class clientTCPgenerique{

    // erhält als Parameter die Merkmale eines Dienstes in der Form
     // Server-Port
     // stellt eine Verbindung zum Dienst her
     // erstellt einen Thread zum Einlesen von über die Tastatur eingegebenen Befehlen
     // diese werden an den Server gesendet
     // erstellt einen Thread zum Lesen der Antworten vom Server
     // diese werden auf dem Bildschirm angezeigt
     // Das Ganze endet mit dem über die Tastatur eingegebenen Befehl „fin“

   // Instanzvariable
  private static Socket client;

    public static void main(String[] args){

         // Syntax
        final String syntaxe="pg serveur port";

         // Anzahl der Argumente
        if(args.length != 2)
            erreur(syntaxe,1);

         // Hier wird der Name des Servers notiert
        String serveur=args[0];

         // Der Port muss eine ganze Zahl > 0 sein
        int port=0;
        boolean erreurPort=false;
        Exception E=null;
        try{
            port=Integer.parseInt(args[1]);
        }catch(Exception e){
            E=e;
            erreurPort=true;
        }
        erreurPort=erreurPort || port <=0;
        if(erreurPort)
            erreur(syntaxe+"\n"+"Port incorrect ("+E+")",2);

        client=null;
         // Es können Probleme auftreten
        try{
             // Verbindung zum Dienst herstellen
            client=new Socket(serveur,port);
        }catch(Exception ex){
             // Fehler
            erreur("Impossible de se connecter au service ("+ serveur
                +","+port+"), erreur : "+ex.getMessage(),3);
             // Ende
            return;
        }//catch

         // Lese-/Schreib-Threads werden erstellt
    new ClientSend(client).start();
    new ClientReceive(client).start();

         // Ende des Haupt-Threads
        return;
    }// main

     // Anzeige der Fehler
    public static void erreur(String msg, int exitCode){
         // Fehleranzeige
        System.err.println(msg);
         // Beenden mit Fehler
        System.exit(exitCode);
    }//Fehler
}//Klasse  

class ClientSend extends Thread {
    // Klasse zum Lesen von über die Tastatur eingegebenen Befehlen
     // und diese über einen als Parameter übergebenen TCP-Client an einen Server zu senden

    private Socket client;    // der TCP-Client

     // Konstruktor
    public ClientSend(Socket client){
         // Hier wird der TCP-Client notiert
        this.client=client;
    }//Konstruktor

     // Run-Methode des Threads
    public void run(){

        // lokale Daten
        PrintWriter OUT=null;            // Netzwerk-Schreibstrom
    BufferedReader IN=null;        // Tastatur-Datenstrom
        String commande=null;            // von der Tastatur gelesener Befehl

         // Fehlerbehandlung
        try{
             // Erstellung des Netzwerk-Schreibstroms
            OUT=new PrintWriter(client.getOutputStream(),true);
      // Erstellung des Tastatureingabestroms
      IN=new BufferedReader(new InputStreamReader(System.in));
            // Schleife für die Eingabe und das Senden von Befehlen
            System.out.println("Commandes : ");
            while(true){
                 // Auslesen des über die Tastatur eingegebenen Befehls
                commande=IN.readLine().trim();
                 // Fertig?
                if (commande.toLowerCase().equals("fin")) break;
                // Befehl an den Server senden
                OUT.println(commande);
                 // Nächster Befehl
            }//while
        }catch(Exception ex){
             // Fehler
            System.err.println("Envoi : L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // Ende – Streams werden geschlossen
        try{
            OUT.close();client.close();
        }catch(Exception ex){}
         // das Ende des Threads wird gemeldet
        System.out.println("[Envoi : fin du thread d'envoi des commandes au serveur]");
    }//run
}//Klasse

class ClientReceive extends Thread{
    // Klasse, die für das Einlesen der Textzeilen zuständig ist, die für einen 
     // als Parameter übergebenen TCP-Client bestimmt sind

    private Socket client;    // der TCP-Client

     // Konstruktor
    public ClientReceive(Socket client){
         // Der TCP-Client wird notiert
        this.client=client;
    }//Konstruktor

     // Run-Methode des Threads
    public void run(){

        // lokale Daten
        BufferedReader IN=null;        // Netzwerk-Lese-Stream
        String réponse=null;        // Serverantwort

         // Fehlerbehandlung
        try{
             // Erstellung des Netzwerk-Lesestreams
            IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
            // Schleife zum Einlesen von Textzeilen aus dem Datenstrom IN
            while(true){
                 // Lesen des Netzwerkstroms
                réponse=IN.readLine();
                 // Datenstrom geschlossen?
                if(réponse==null) break;
                // Anzeige
                System.out.println("<-- "+réponse);
            }//while
        }catch(Exception ex){
            // Fehler
            System.err.println("Réception : L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // Ende – die Datenströme werden geschlossen
        try{
            IN.close();client.close();
        }catch(Exception ex){}
         // das Ende des Threads wird gemeldet
        System.out.println("[Réception : fin du thread de lecture des réponses du serveur]");
    }//run
}//Klasse

8.2.2. Der generische TCP-Server

Nun wenden wir uns einem Server zu,

  • , der die von seinen Clients gesendeten Befehle auf dem Bildschirm anzeigt
  • und ihnen als Antwort die Textzeilen zurücksendet, die ein Benutzer über die Tastatur eingegeben hat. Letzterer fungiert also als Server.

Das Programm wird gestartet mit: java serveurTCPgenerique portEcoute, wobei portEcoute der Port ist, über den sich die Clients verbinden müssen. Die Bedienung der Clients wird von zwei Threads übernommen:

  • ein Thread, der sich ausschließlich dem Einlesen der vom Client gesendeten Textzeilen widmet
  • ein Thread, der sich ausschließlich dem Einlesen der vom Benutzer über die Tastatur eingegebenen Antworten widmet. Dieser signalisiert mit dem Befehl „fin“, dass er die Verbindung zum Client beendet.

Der Server erstellt zwei Threads pro Client. Bei n Clients sind somit 2n Threads gleichzeitig aktiv. Der Server selbst wird niemals beendet, es sei denn, der Benutzer drückt die Tastenkombination Strg+C. Sehen wir uns einige Beispiele an.

Der Server wird auf Port 100 gestartet, und wir verwenden den generischen Client, um mit ihm zu kommunizieren. Das Client-Fenster sieht wie folgt aus:

E:\data\serge\MSNET\c#\Netzwerk\generischer TCP-Client> java clientTCPgenerique localhost 100
Commandes :
commande 1 du client 1
<-- réponse 1 au client 1
commande 2 du client 1
<-- réponse 2 au client 1
fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du thread de lecture des réponses du serveur]
[fin du thread d'envoi des commandes au serveur]

Die Zeilen, die mit <-- beginnen, sind vom Server an den Client gesendet worden, die anderen vom Client an den Server. Das Serverfenster sieht wie folgt aus:


Dos> java serveurTCPgenerique 100
Serveur générique lancé sur le port 100
Thread de lecture des réponses du serveur au client 1 lancé
1 : Thread de lecture des demandes du client 1 lancé
<-- commande 1 du client 1
réponse 1 au client 1
1 : <-- commande 2 du client 1
réponse 2 au client 1
1 : [fin du Thread de lecture des demandes du client 1]
fin
[fin du Thread de lecture des réponses du serveur au client 1]

Die mit <-- beginnenden Zeilen sind diejenigen, die vom Client an den Server gesendet wurden. Die Zeilen N: sind die Zeilen, die vom Server an den Client Nr. N gesendet wurden. Der oben genannte Server ist noch aktiv, während Client 1 beendet wurde. Wir starten einen zweiten Client für denselben Server:


Dos> java clientTCPgenerique localhost 100
Commandes :
commande 3 du client 2
<-- réponse 3 au client 2
fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du thread de lecture des réponses du serveur]
[fin du thread d'envoi des commandes au serveur]

Das Serverfenster sieht dann wie folgt aus:


Dos> java serveurTCPgenerique 100
Serveur générique lancé sur le port 100
Thread de lecture des réponses du serveur au client 1 lancé
1 : Thread de lecture des demandes du client 1 lancé
<-- commande 1 du client 1
réponse 1 au client 1
1 : <-- commande 2 du client 1
réponse 2 au client 1
1 : [fin du Thread de lecture des demandes du client 1]
fin
[fin du Thread de lecture des réponses du serveur au client 1]
Thread de lecture des réponses du serveur au client 2 lancé
2 : Thread de lecture des demandes du client 2 lancé
<-- commande 3 du client 2
réponse 3 au client 2
2 : [fin du Thread de lecture des demandes du client 2]
fin
[fin du Thread de lecture des réponses du serveur au client 2]
^C

Simulieren wir nun einen Webserver, indem wir unseren generischen Server auf Port 88 starten:


Dos> java serveurTCPgenerique 88
Serveur générique lancé sur le port 88

Öffnen wir nun einen Browser und rufen wir die Seite URL http://localhost:88/exemple.html auf. Der Browser stellt dann eine Verbindung zum Port 88 des Rechners localhost her und fordert anschließend die Seite /exemple.html an:

Image

Sehen wir uns nun das Fenster unseres Servers an:

Dos>java serveurTCPgenerique 88
Serveur générique lancé sur le port 88
Thread de lecture des réponses du serveur au client 2 lancé
2 : Thread de lecture des demandes du client 2 lancé
<-- GET /exemple.html HTTP/1.1
<-- Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/msword, */*
<-- Accept-Language: fr
<-- Accept-Encoding: gzip, deflate
<-- User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.0.2
914)
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--

So entdecken wir die vom Browser gesendeten Header HTTP. Dies ermöglicht es uns, das Protokoll HTTP nach und nach zu entschlüsseln. In einem früheren Beispiel hatten wir einen Web-Client erstellt, der lediglich den Befehl GET sendete. Das hatte ausgereicht. Hier sehen wir, dass der Browser weitere Informationen an den Server sendet. Diese dienen dazu, dem Server mitzuteilen, um welche Art von Client es sich handelt. Wir sehen auch, dass die Header HTTP mit einer leeren Zeile enden.

Erstellen wir eine Antwort für unseren Client. Der Benutzer an der Tastatur ist hier der eigentliche Server und kann eine Antwort manuell erstellen. Erinnern wir uns an die Antwort eines Webservers aus einem früheren Beispiel:

<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix)  (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>

Versuchen wir, eine ähnliche Antwort zu geben:

...
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--
2 : HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :
2 : <html>
2 :   <head><title>Serveur generique</title></head>
2 :   <body>
2 :     <center>
2 :       <h2>Reponse du serveur generique</h2>
2 :     </center>
2 :    </body>
2 : </html>
2 : fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du Thread de lecture des demandes du client 2]
[fin du Thread de lecture des réponses du serveur au client 2]

Zeilen, die mit „2:“ beginnen, werden vom Server an Client Nr. 2 gesendet. Der Befehl fin beendet die Verbindung vom Server zum Client. Wir haben uns in unserer Antwort auf die folgenden HTTP-Header beschränkt:

HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :

Wir geben die Größe der Datei, die wir senden werden (Content-Length), nicht an, sondern geben lediglich an, dass wir die Verbindung (Connection: close) nach dem Senden dieser Datei schließen werden. Das reicht für den Browser aus. Sobald der Browser sieht, dass die Verbindung geschlossen wurde, weiß er, dass die Antwort des Servers abgeschlossen ist, und zeigt die Seite HTML an, die ihm gesendet wurde. Diese lautet wie folgt:

2 : <html>
2 :   <head><title>Serveur generique</title></head>
2 :   <body>
2 :     <center>
2 :       <h2>Reponse du serveur generique</h2>
2 :     </center>
2 :    </body>
2 : </html>

Der Benutzer beendet anschließend die Verbindung zum Client, indem er den Befehl fin eingibt. Der Browser erkennt daraufhin, dass die Antwort des Servers abgeschlossen ist, und kann sie nun anzeigen:

Image

Wenn man oben den Befehl View/Source eingibt, um zu sehen, was der Browser empfangen hat, erhält man:

Image

Das ist genau das, was vom generischen Server gesendet wurde.

Der Code des generischen TCP-Servers lautet wie folgt:

// Pakete
import java.io.*;
import java.net.*;

public class serveurTCPgenerique{

     // Hauptprogramm
    public static void main (String[] args){

    // empfängt über den Listening-Port Anfragen von Clients
     // erstellt einen Thread zum Lesen der Client-Anfragen
     // diese werden auf dem Bildschirm angezeigt
     // erstellt einen Thread zum Einlesen von über die Tastatur eingegebenen Befehlen
     // Diese werden als Antwort an den Kunden gesendet
     // Das Ganze endet mit dem über die Tastatur eingegebenen Befehl end

    final String syntaxe="Syntaxe : pg port";
   // Instanzvariable
         // Gibt es ein Argument?
     if(args.length != 1)
        erreur(syntaxe,1);

         // Der Port muss eine ganze Zahl > 0 sein
        int port=0;
        boolean erreurPort=false;
        Exception E=null;
        try{
            port=Integer.parseInt(args[0]);
        }catch(Exception e){
            E=e;
            erreurPort=true;
        }
        erreurPort=erreurPort || port <=0;
        if(erreurPort)
            erreur(syntaxe+"\n"+"Port incorrect ("+E+")",2);

     // Der Listening-Dienst wird erstellt
    ServerSocket ecoute=null;
    int nbClients=0;    // Anzahl der bedienten Clients
        try{
             // Der Dienst wird erstellt
            ecoute=new ServerSocket(port);
             // Weiterverfolgung
            System.out.println("Serveur générique lancé sur le port " + port);

             // Schleife für die Kundenbetreuung
            Socket client=null;
            while (true){ // Endlosschleife  wird mit Strg+C beendet
                 // Warten auf einen Client
                client=ecoute.accept();

                 // Der Dienst wird von separaten Threads ausgeführt
                nbClients++;

                 // Lese-/Schreib-Threads werden erstellt
        new ServeurSend(client,nbClients).start();
        new ServeurReceive(client,nbClients).start();

                // Es wird wieder auf Anfragen gewartet
            }// Ende der while-Schleife
        }catch(Exception ex){
             // Der Fehler wird gemeldet
            erreur("L'erreur suivante s'est produite : " + ex.getMessage(),3);
        }//catch
    }// Ende von main

     // Anzeige der Fehler
    public static void erreur(String msg, int exitCode){
         // Fehleranzeige
        System.err.println(msg);
         // Beenden mit Fehler
        System.exit(exitCode);
    }//Fehler
}//Klasse

class ServeurSend extends Thread{
    // Klasse zum Einlesen von über die Tastatur eingegebenen Antworten
     // und diese über einen an den Konstruktor übergebenen TCP-Client an einen Client zu senden

    Socket client;    // der TCP-Client
    int numClient;        // Client-Nr.

     // Konstruktor
    public ServeurSend(Socket client, int numClient){
         // wird der TCP-Client notiert
        this.client=client;
         // sowie dessen Nummer
        this.numClient=numClient;
    }//Hersteller

     // Run-Methode des Threads
    public void run(){

        // lokale Daten
        PrintWriter OUT=null;        // Netzwerk-Schreibstrom
        String réponse=null;        // von der Tastatur gelesene Antwort
    BufferedReader IN=null;    // Tastatur-Datenstrom

        // Überwachung
        System.out.println("Thread de lecture des réponses du serveur au client "+ numClient + " lancé");
         // Fehlerbehandlung
        try{
             // Erstellung des Netzwerk-Schreibstroms
            OUT=new PrintWriter(client.getOutputStream(),true);
      // Erstellung des Tastatur-Datenstroms
      IN=new BufferedReader(new InputStreamReader(System.in));
            // Schleife Befehlseingabe und -übertragung
            while(true){
                 // Kundenidentifikation
                System.out.print("--> " + numClient + " : ");
                 // Auslesen der über die Tastatur eingegebenen Antwort
                réponse=IN.readLine().trim();
                // Fertig?
                if (réponse.toLowerCase().equals("fin")) break;
                // Antwort an den Server senden
                OUT.println(réponse);
                 // Nächste Antwort
            }//while
        }catch(Exception ex){
             // Fehler
            System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // Ende  Streams werden geschlossen
        try{
            OUT.close();client.close();
        }catch(Exception ex){}
         // das Ende des Threads wird gemeldet
        System.out.println("[fin du Thread de lecture des réponses du serveur au client "+ numClient+ "]");
    }//run
}//Klasse

class ServeurReceive extends Thread{
    // Klasse, die für das Einlesen der an den Server gesendeten Textzeilen zuständig ist 
     // über einen an den Konstruktor übergebenen TCP-Client

    Socket client;    // der TCP-Client
    int numClient;        // Client-Nr.

     // Konstruktor
    public ServeurReceive(Socket client, int numClient){
         // der TCP-Client wird notiert
        this.client=client;
         // sowie dessen Nummer
        this.numClient=numClient;
    }//Hersteller

     // Run-Methode des Threads
    public void run(){

        // lokale Daten
        BufferedReader IN=null;        // Netzwerk-Lese-Stream
        String réponse=null;        // Serverantwort

         // Nachverfolgung
        System.out.println("Thread de lecture des demandes du client "+ numClient + " lancé");
         // Fehlerbehandlung
        try{
             // Erstellung des Netzwerk-Lesestreams
            IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
            // Schleife zum Einlesen der Textzeilen aus dem Datenstrom IN
            while(true){
                 // Netzwerk-Stream lesen
                réponse=IN.readLine();
                 // Datenstrom geschlossen?
                if(réponse==null) break;
                // Anzeige
                System.out.println("<-- "+réponse);
            }//while
        }catch(Exception ex){
            // Fehler
            System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // Ende  die Datenströme werden geschlossen
        try{
            IN.close();client.close();
        }catch(Exception ex){}
         // das Ende des Threads wird gemeldet
        System.out.println("[fin du Thread de lecture des demandes du client "+ numClient+"]");
    }//run
}//Klasse

8.3. JAVASCRIPT

In diesem Abschnitt zeigen wir drei Beispiele für die Verwendung von JavaScript auf den Seiten WEB. Wir konzentrieren uns dabei auf die Formularverwaltung, doch JavaScript kann noch viel mehr.

8.3.1. Daten aus einem Formular abrufen

Das folgende Beispiel zeigt, wie die vom Benutzer in ein Formular eingegebenen Daten im Browser abgerufen werden können. Dies ermöglicht in der Regel eine Vorverarbeitung, bevor die Daten an den Server gesendet werden.

8.3.1.1. Das Formular

Wir haben ein Formular, das die gängigsten Komponenten enthält, sowie eine Schaltfläche „Anzeigen“, mit der die vom Benutzer vorgenommenen Eingaben angezeigt werden können.

Image

8.3.1.2. Der Code

<html>

  <head>
    <title>Un formulaire traité par Javascript</title>
    <script language="javascript">
      function afficher(){
         // zeigt die Formularinformationen in einer Liste an

         // zuerst löschen
        effacerInfos();

         // man zeigt den Wert der # Felder an
        with(document.frmExemple){
           // verstecktes Feld
          ecrire("champ caché="+cache.value);
           // einfaches Textfeld
          ecrire("champ textuel simple="+simple.value);
           // Mehrfachtextfeld
          ecrire("champ textuel multiple="+lignes.value);
          // Optionsfelder
          for(i=0;i<radio.length;i++){
            texte="radio["+i+"]="+radio[i].value;
            if(radio[i].checked) texte+=", coché";
            ecrire(texte);
          }//for
             // Kontrollkästchen
          for(i=0;i<qcm.length;i++){
            texte="qcm["+i+"]="+qcm[i].value;
            if(qcm[i].checked) texte+=", coché";
            ecrire(texte);
          }//für
           //Dropdown-Liste
          ecrire("index sélectionné dans le menu="+menu.selectedIndex);
          for(i=0;i<menu.length;i++){
            texte="menu["+i+"]="+menu.options[i].text;
            if(menu.options[i].selected) texte+=",sélectionné";
            ecrire(texte);
          }//für
           //Mehrfachauswahlliste
          for(i=0;i<lstVoitures.length;i++){
            texte="lstVoitures["+i+"]="+lstVoitures.options[i].text;
            if(lstVoitures.options[i].selected) texte+=",sélectionné";
            ecrire(texte);
          }//für
           //Passwort
          ecrire("mot de passe="+passwd.value);
        }//mit
      }//Funktion

      function ecrire(texte){
         // schreibt Text in die Informationsliste
        frmInfos.lstInfos.options[frmInfos.lstInfos.length]=new Option(texte);
      }//schreiben

      function effacerInfos(){
        frmInfos.lstInfos.length=0;
      }//effacerInfos
    </script>
  </head>

  <body bgcolor="#C0C0C0" onload="afficher()">
    <center>
     <h2>Un formulaire traité par Javascript</h2>
    <hr>
    <form method="POST" name="frmExemple">
        <input type="hidden" name="cache" value="secret">
        <table border="0">
        <tr>
            <td align="center">Un champ textuel simple</td>
            <td align="center" width="100">&nbsp;</td>
            <td align="center">Un champ textuel sur plusieurs lignes</td>
        </tr>
        <tr>
            <td align="center"><input type="text" size="20" name="simple"></td>
            <td align="center" width="100">&nbsp;</td>
            <td align="center">
              <textarea name="lignes" rows="2" cols="40">Ce texte est modifiable</textarea>
            </td>
        </tr>
    </table>
    <table border="0">
      <tr>
       <td><strong>Des boutons radio :</strong></td>
        <td>
          <input type="radio" checked name="radio" value="FM">FM
        </td>
        <td>
          <input type="radio" name="radio" value="GO">GO
        </td>
        <td>
          <input type="radio" name="radio" value="PO">PO
        </td>
        <td>&nbsp;</td>
        <td><strong>Des choix multiples :</strong></td>
        <td>
          <input type="checkbox" name="qcm" value="un">un
        </td>
        <td>
          <input type="checkbox" name="qcm" value="deux">deux
        </td>
        <td>
          <input type="checkbox" name="qcm" value="trois">trois
        </td>
     </tr>
    </table>
    <table border="0">
      <tr>
       <td>Un menu déroulant : </td>
        <td>
          <select name="menu" size="1">
             <option>50 F</option>
              <option>60 F</option>
              <option>70 F</option>
              <option>100 F</option>
            </select>
        </td>
          <td>Une liste :</td>
           <td>
             <select name="lstVoitures" multiple size="3">
                <option>Renault</option>
                <option>Citroën</option>
                <option>Peugeot</option>
                <option>Fiat</option>
                <option>Audi</option>
              </select>
           </td>
        </tr>
    </table>
    <table border="0">
        <tr>
            <td>Un mot de passe : </td>
            <td><input type="password" size="21" name="passwd"></td>
            <td>&nbsp;</td>
            <td>Un champ de contexte caché : </td>
        </tr>
    </table>
    </form>
    <hr>
    <h2>Informations du formulaire</h2>
    <form name="frmInfos">
      <table>
        <tr>
          <td><input type="button" value="Effacer" onclick="effacerInfos()"></td>
          <td>
            <select name="lstInfos" multiple size="3">
            </select>
          </td>
          <td>
            <input type="button" name="cmdAfficher" value="Afficher" onclick="afficher()">
          </td>
        </tr>
    </form>
  </body>
</html>

8.3.2. Reguläre Ausdrücke in JavaScript

Auf der Browserseite kann JavaScript verwendet werden, um die Gültigkeit der vom Benutzer eingegebenen Daten zu überprüfen, bevor diese an den Server gesendet werden. Hier ist ein Programm zum Testen dieser regulären Ausdrücke.

8.3.2.1. Die Testseite

Image

8.3.2.2. Der Code der Seite

<html>

  <head>
    <title>Les expressions régulières en Javascript</title>
    <script language="javascript">
      function afficherInfos(){
        with(document.frmRegExp){
           // Gibt es etwas zu tun?
          if (! verifier()) return;
          // Alles klar – die vorherigen Ergebnisse werden gelöscht
          effacerInfos();
           // Überprüfung der Vorlage
          modele=new RegExp(txtModele.value);
          champs=modele.exec(txtChaine.value);
          if(champs==null)
             // Keine Übereinstimmung zwischen Muster und Zeichenfolge
            ecrireInfos("pas de correspondance");
          else{
             // Übereinstimmung – die Ergebnisse werden angezeigt
            ecrireInfos("Il y a correspondance");
            for(i=0;i<champs.length;i++)
              ecrireInfos("champs["+i+"]=["+champs[i]+"]");
          }//sonst
        }//mit
      }//Funktion

      function ecrireInfos(texte){
        // schreibt Text in die Informationsliste
        document.frmRegExp.lstInfos.options[document.frmRegExp.lstInfos.length]=new Option(texte);
      }//schreiben

      function effacerInfos(){
        frmRegExp.lstInfos.length=0;
      }//effacerInfos

      function jouer(){
         // prüft die Vorlage anhand der Zeichenfolge im ausgewählten Beispiel
        with(document.frmRegExp){
          txtModele.value=lstModeles.options[lstModeles.selectedIndex].text
          txtChaine.value=lstChaines.options[lstChaines.selectedIndex].text
          afficherInfos();
        }//mit
      }//abspielen

      function ajouter(){
         //fügt den aktuellen Test zu den Beispielen hinzu
        with(document.frmRegExp){
          // Gibt es etwas zu tun?
          if (! verifier()) return;
           // Hinzufügen
          lstModeles.options[lstModeles.length]=new Option(txtModele.value);
          lstChaines.options[lstChaines.length]=new Option(txtChaine.value);
           // Eingaben löschen
          txtModele.value="";
          txtChaine.value="";
        }//mit
      }//hinzufügen

      function verifier(){
         // Prüft, ob die Eingabefelder nicht leer sind
        with(document.frmRegExp){
          champs=/^\s*$/.exec(txtModele.value);
          if(champs!=null){
            alert("Vous n'avez pas indiqué de modèle");
            txtModele.focus();
            return false;
          }//if
          champs=/^\s*$/.exec(txtChaine.value);
          if(champs!=null){
            alert("Vous n'avez pas indiqué de chaîne de test");
            txtChaine.focus();
            return false;
          }//wenn
           // alles in Ordnung
          return true;
        }//mit
      }//prüfen
    </script>
  </head>

  <body bgcolor="#C0C0C0">
    <center>
     <h2>Les expressions régulières en Javascript</h2>
    <hr>
    <form name="frmRegExp">
      <table>
        <tr>
          <td>Expression régulière</td>
          <td>Chaîne de test</td>
        </tr>
        <tr>
          <td><input type="text" name="txtModele" size="20"></td>
          <td><input type="text" name="txtChaine" size="20"></td>
        </tr>
        <tr>
          <td>
            <input type="button" name="cmdAfficher" value="Jouer le test" onclick="afficherInfos()">
          </td>
          <td>
            <input type="button" name="cmdAjouter" value="Ajouter aux exemples" onclick="ajouter()">
          </td>
        </tr>
      </table>
      <hr>
      <h2>Résultats de l'instruction champs=expression régulière.exec(chaine)</h2>
      <table>
        <tr>
          <td>
            <select name="lstInfos" size="3">
            </select>
          </td>
        </tr>
      </table>
      <hr>
      <h2>Exemples</h2>
      <table>
 <tr>
          <td align="center">Modèles</td>
          <td align="center">Chaînes</td>
        </tr>
        <tr>
          <td>
            <select name="lstModeles" size="1">
              <option>^\d+$</option>
              <option>^(\d+) (\d+)$</option>
              <option>^(\d+)(.*)(\d+)$</option>
              <option>^(\d+)(\s+)(\d+)$</option>
            </select>
          </td>
          <td>
            <select name="lstChaines" size="1">
              <option>67</option>
              <option>56 84</option>
              <option>45abcd67</option>
              <option>45   67</option>
            </select>
          </td>
          <td>
            <input type="button" name="cmdJouer" value="Jouer l'exemple" onclick="jouer()">
          </td>
        </tr>
    </form>
  </body>
</html>

8.3.3. Listenverwaltung in JavaScript

8.3.3.1. Das Formular

Image

8.3.3.2. Der Code

<html>

  <head>
    <title>Les listes en Javascript</title>

    <script language="javascript">
       // hinzufügen
      function ajouter(L1,L2,T){
         // fügt den Wert des Feldes T zu den Listen L1 und L2 hinzu
           // Muss etwas unternommen werden?
          champs=/^\s*$/.exec(T.value);
          if(champs!=null){
            // Das Feld ist leer
            alert("Vous n'avez pas indiqué la valeur à ajouter");
            txtElement.focus();
            return;
          }//if
           // wird das Element hinzugefügt
          L1.options[L1.length]=new Option(T.value);
          L2.options[L2.length]=new Option(T.value);
          T.value="";
      }//Hinzufügen

       //leeren
      function vider(L){
         // leert die Liste L
        L.length=0;
      }//leeren

      //übertragen
      function transfert(L1,L2,simple){
        //überträgt die in der Liste L1 ausgewählten Elemente in L2

         // Muss etwas getan werden?
         // Index des in L1 ausgewählten Elements
        index1=L1.selectedIndex;
        if(index1==-1){
          alert("Vous n'avez pas sélectionné d'élément");
          return;
        }//if
         // Wie erfolgt die Auswahl der Elemente aus den Listen?
        if(simple){ // Einfache Auswahl
          element1=L1.options[index1].text;
           //Hinzufügen in L2
          L2.options[L2.length]=new Option(element1);
          //Löschen in L1
          L1.options[index1]=null;
        }//einfach
        if(! simple){ //Mehrfachauswahl
           //Liste 1 in umgekehrter Reihenfolge durchlaufen
          for(i=L1.length-1;i>=0;i--){
            //Element ausgewählt?
            if(L1.options[i].selected){
               //wird zu L2 hinzugefügt
              L2.options[L2.length]=new Option(L1.options[i].text);
              //aus L1 entfernen
              L1.options[i]=null;
            }//if
          }//für i
        }//if ! einfach
      }//Übertragung
   </script>
  </head>

  <body bgcolor="#C0C0C0">
    <center>
     <h2>Les listes en Javascript</h2>
    <hr>
    <form name="frmListes">
      <table>
        <tr>
          <td>
            <input type="button" name="cmdAjouter" value="Ajouter" onclick="ajouter(lst1A,lst1B,txtElement)">
          </td>
          <td>
            <input type="text" name="txtElement">
          </td>
        </tr>
      </table>
      <table>
        <tr>
          <td align="center">liste 1</td>
          <td align="center"><input type="button" value=">>" onclick="transfert(lst1A,lst2A,true)"</td>
          <td align="center"><input type="button" value="<<" onclick="transfert(lst2A,lst1A,true)"</td>
          <td align="center">liste 2</td>
          <td width="30"></td>
          <td align="center">liste 1</td>
          <td align="center"><input type="button" value=">>" onclick="transfert(lst1B,lst2B,false)"</td>
          <td align="center"><input type="button" value="<<" onclick="transfert(lst2B,lst1B,false)"</td>
          <td align="center">liste 2</td>
        </tr>
         <tr>
          <td></td>
          <td align="center">
            <select name="lst1A" size="5">
            </select>
          </td>
          <td align="center">
            <select name="lst2A" size="5">
            </select>
          </td>
          <td></td>
          <td></td>
          <td></td>
          <td align="center">
            <select name="lst1B" size="5" multiple >
            </select>
          </td>
          <td align="center">
            <select name="lst2B" size="5" multiple>
            </select>
          </td>

        </tr>
        <tr>
          <td></td>
          <td align="center"><input type="button" value="Vider" onclick="vider(lst1A)"</td>
          <td align="center"><input type="button" value="Vider" onclick="vider(lst2A)"</td>
          <td></td>
          <td></td>
          <td></td>
          <td align="center"><input type="button" value="Vider" onclick="vider(lst1B)"</td>
          <td align="center"><input type="button" value="Vider" onclick="vider(lst2B)"</td>
          <td></td>
        </tr>
        <tr>
          <td></td>
          <td colspan="2"><strong>Sélection simple</strong></td>
          <td></td>
          <td></td>
          <td></td>
          <td colspan="2"><strong>Sélection multiple</strong></td>
          <td></td>
        </tr>

      </table>
      <hr>
    </form>
  </body>
</html>