Skip to content

8. Bijlagen

8.1. Hulpmiddelen voor webontwikkeling

Hier geven we aan waar je de benodigde tools voor webontwikkeling kunt vinden en hoe je ze kunt installeren. Sommige tools zijn in versie gewijzigd en het kan zijn dat de hier gegeven uitleg niet meer van toepassing is op de meest recente versies. De lezer zal zich dan moeten aanpassen... In de cursus webprogrammering zullen we voornamelijk de volgende tools gebruiken, die allemaal gratis beschikbaar zijn:

  • een recente browser die XML kan weergeven. De voorbeelden uit de cursus zijn getest met Internet Explorer 6.
  • een recente JDK (Java Development Kit). De voorbeelden uit de cursus zijn getest met JDK 1.4. Deze JDK bevat de Java 1.4-plug-in voor browsers, waardoor deze Java-applets kunnen weergeven die gebruikmaken van Java 1.4.
  • een Java-ontwikkelomgeving voor het schrijven van Java-servlets. Hier is dat JBuilder 7.
  • webservers: Apache, PWS (Personal Web Server), Tomcat.
    • Apache zal worden gebruikt voor de ontwikkeling van webapplicaties in PERL (Practical Extracting and Reporting Language) of PHP (Personal Home Page)
    • PWS zal worden gebruikt voor de ontwikkeling van webapplicaties in ASP (Active Server Pages) of PHP
    • Tomcat zal worden gebruikt voor de ontwikkeling van webapplicaties met behulp van Java-servlets of JSP-pagina's (Java Server Pages)
  • een applicatie voor databasebeheer: MySQL
  • EasyPHP: een tool die de Apache-webserver, de taal PHP en SGBD MySQL samenbrengt

8.1.1. Webservers, browsers, scripttalen

  1. Belangrijkste webservers
    • Apache (Linux, Windows)
    • Interner Information Server IIS (NT), Personal Web Server PWS (Windows 9x)
  1. Belangrijkste browsers
    • Internet Explorer (Windows)
    • Netscape (Linux, Windows)
  1. Server-side scripttalen
    • VBScript (IIS, PWS)
    • JavaScript (IIS, PWS)
    • Perl (Apache, IIS, PWS)
    • PHP (Apache, IIS, PWS)
    • Java (Apache, Tomcat)
    • Talen .NET
  1. Scripttalen aan de browserzijde
    • VBScript (IE)
    • JavaScript (IE, Netscape)
    • PerlScript (IE)
    • Java (IE, Netscape)

8.1.2. Waar vind je de tools

Netscape
http://www.netscape.com/ (downloadlink)
Internet Explorer
http://www.microsoft.com/windows/ie/default.asp
PHP
http://www.php.net
http://www.php.net/downloads.php (Windows-binaries)
PERL
http://www.activestate.com http://www.activestate.com/Products/
http://www.activestate.com/Products/ActivePerl/
Vbscript, Javascript
http://msdn.microsoft.com/scripting (volg de link naar het Windows-script)
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
opgenomen in NT 4.0 Option Pack voor Windows 95
opgenomen in CD voor 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

Deze applicatie is erg handig omdat het in één pakket het volgende bevat:

  • de Apache-webserver (1.3.x)
  • de taal PHP (4.x)
  • de SGBD MySQL (3.23.x)
  • een beheerprogramma voor MySQL: PhpMyAdmin

De installatieapplicatie ziet er als volgt uit:

Image

De installatie van EasyPHP verloopt probleemloos en er wordt een mappenstructuur aangemaakt in het bestandssysteem:

Image

easyphp.exe
het uitvoerbare bestand van de applicatie
apache
de directorystructuur van de Apache-server
mysql
de MySQL-structuur van SGBD
phpmyadmin
de directorystructuur van de phpMyAdmin-applicatie
php
de directorystructuur van php
www
de hoofdmap van de webpagina's die door de Apache-server van EasyPHP worden geleverd
cgi-bin
mappenstructuur waarin CGI-scripts voor de Apache-server kunnen worden geplaatst

Het belangrijkste voordeel van EasyPHP is dat de applicatie vooraf geconfigureerd wordt geleverd. Apache, PHP en MySQL zijn dus al geconfigureerd om samen te werken. Wanneer u EasyPhp start via de snelkoppeling in het programmamenu, verschijnt er een pictogram rechtsonder op het scherm.

De E met een rode stip moet knipperen als de webserver Apache en de database MySQL operationeel zijn. Als je er met de rechtermuisknop op klikt, verschijnen er menuopties:

Image

Met de optie Administration kun je instellingen aanpassen en controleren of alles goed werkt:

Image

8.1.3.1. Beheer PHP

Met de knop ‘php-info’ kunt u controleren of de combinatie Apache-PHP correct werkt: er verschijnt dan een informatiepagina PHP:

Image

De knop ‘Extensies’ toont de lijst met geïnstalleerde extensies voor PHP. Dit zijn in feite bibliotheken met functies.

Image

Het bovenstaande scherm laat bijvoorbeeld zien dat de functies die nodig zijn voor het gebruik van de database MySQL inderdaad aanwezig zijn.

De knop ‘Instellingen’ toont de login/motdepasse van de beheerder van de database MySQL.

Image

Het gebruik van de database MySQL valt buiten het bestek van deze korte presentatie, maar het is hier duidelijk dat er een wachtwoord moet worden ingesteld voor de databasebeheerder.

8.1.3.2. Apache-beheer

Nog steeds op de beheerpagina van EasyPHP kunt u via de link ‘uw aliassen’ aliassen instellen die aan een map zijn gekoppeld. Hierdoor kunt u webpagina’s elders plaatsen dan in de map www van de boomstructuur van easyPhp.

Image

Als u op de bovenstaande pagina de volgende gegevens invoert:

Image

en de knop valider gebruikt, worden de volgende regels toegevoegd aan het bestand <easyphp>\apache\conf\httpd.conf:

    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> verwijst naar de installatiemap van EasyPHP. httpd.conf is het configuratiebestand van de Apache-server. Je kunt dus hetzelfde doen door dit bestand rechtstreeks te bewerken. Een wijziging in het bestand httpd.conf wordt normaal gesproken onmiddellijk door Apache verwerkt. Als dat niet het geval is, moet je de server stoppen en vervolgens opnieuw starten, altijd via het EasyPHP-pictogram:

Image

Om ons voorbeeld af te ronden, kunnen we nu webpagina’s in de mapstructuur e:\data\serge\web plaatsen:

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

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

en deze pagina opvragen met behulp van de alias st:

Image

In dit voorbeeld is de Apache-server geconfigureerd om op poort 81 te werken. De standaardpoort is 80. Dit wordt bepaald door de volgende regel in het reeds genoemde bestand httpd.conf:

Port 81

8.1.3.3. Het Apache-configuratiebestand htpd.conf

Als je Apache wat gedetailleerder wilt configureren, moet je het configuratiebestand httpd.conf, dat zich hier in de map <easyphp>\apache\conf bevindt, “met de hand” aanpassen:

Image

Hier volgen enkele belangrijke punten uit dit configuratiebestand:

ligne(s)
rol
ServerRoot "D:/Program Files/Apache Group/Apache"
geeft de map aan waarin de Apache-structuur zich bevindt
Port 80
geeft aan op welke poort de webserver zal werken. Meestal is dit 80. Door deze regel te wijzigen, kan de webserver op een andere poort worden ingesteld
ServerAdmin root@istia.univ-angers.fr
het e-mailadres van de beheerder van de Apache-server
ServerName stahe.istia.uang
de naam van de machine waarop de Apache-server „draait“
ServerRoot "E:/Program Files/EasyPHP/apache"
de installatiemap van de Apache-server. Wanneer er in het configuratiebestand relatieve bestandsnamen voorkomen, zijn deze relatief ten opzichte van deze map.
DocumentRoot "E:/Program Files/EasyPHP/www"
de hoofdmap van de boomstructuur van de webpagina’s die door de server worden geleverd. Hier komt de URL http://machine/rep1/fic1.html overeen met het bestand E:\Program Files\EasyPHP\www\rep1\fic1.html
<Directory "E:/Program Files/EasyPHP/www">
stelt de eigenschappen van de vorige map in
ErrorLog logs/error.log
logmap, dus in feite <ServerRoot>\logs\error.log: E:\Program Files\EasyPHP\apache\logs\error.log. Dit is het bestand dat u moet raadplegen als u merkt dat de Apache-server niet werkt.
    ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/"
E:\Program Files\EasyPHP\cgi-bin is de hoofdmap van de directorystructuur waar u CGI-scripts kunt plaatsen. De URL van het script CGI is dus URL http://machine/cgi-bin/rep1/script1.pl E:\Program Files\EasyPHP\cgi-bin\rep1\script1.pl.
<Directory "E:/Program Files/EasyPHP/cgi-bin/">
stelt de eigenschappen van de bovenstaande map in
LoadModule php4_module "E:/Program
 Files/EasyPHP/php/php4apache.dll"
AddModule mod_php4.c
laadregels voor de modules waarmee Apache met PHP4 kan werken.
    AddType application/x-httpd-php
 .phtml .pwml .php3 
.php4 .php .php2 .inc
stelt de bestandsextensies vast die moeten worden beschouwd als bestanden die door PHP moeten worden verwerkt

8.1.3.4. Beheer van MySQL met PhpMyAdmin

Op de beheerpagina van EasyPhp klikt u op de knop PhpMyAdmin:

Image

Via de vervolgkeuzelijst onder Accueil kunt u de
.
Het getal tussen haakjes is het aantal tabellen. Als je
een database selecteert, worden de tabellen daarin weergegeven:

De webpagina biedt een aantal bewerkingen op de database:

Image

Als je op de link Afficher van user klikt:

Image

Er is hier slechts één gebruiker: root, de beheerder van MySQL. Door de link Modifier te volgen, zou men het wachtwoord kunnen wijzigen, dat momenteel leeg is, wat niet aan te raden is voor een beheerder.

We zullen verder niets zeggen over PhpMyAdmin, een veelzijdig programma dat een uitgebreide beschrijving van meerdere pagina’s zou verdienen.

8.1.4. PHP

We hebben gezien hoe je PHP kunt verkrijgen via de applicatie EasyPhp. Om PHP rechtstreeks te verkrijgen, ga je naar de website http://www.php.net.

PHP is niet alleen bruikbaar op het web. Je kunt het ook als scripttaal onder Windows gebruiken. Maak het volgende script aan en sla het op onder de naam date.php:

<?
   // PHP-script dat de tijd weergeeft
  $maintenant=date("j/m/y, H:i:s",time());
  echo "Nous sommes le $maintenant";
?>

Ga in een venster met de naam DOS naar de map van date.php en voer het programma uit:

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

Het is aan te raden dat Internet Explorer al is geïnstalleerd. Als dit het geval is, zal Active Perl het zo configureren dat het PERL-scripts in de HTML-pagina's accepteert; deze scripts worden vervolgens door IE zelf aan de clientzijde uitgevoerd. De website van Active Perl is te vinden op URL http://www.activestate.comA. Na de installatie wordt PERL geïnstalleerd in een map die we <perl> zullen noemen. Deze bevat de volgende mapstructuur:

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

Het uitvoerbare bestand perl.exe bevindt zich in <perl>\bin. Perl is een scripttaal die onder Windows en Unix draait. Het wordt bovendien gebruikt bij het programmeren van WEB. Laten we een eerste script schrijven:

# script PERL dat de tijd weergeeft

# modules
use strict;

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

Sla dit script op in een bestand met de naam heure.pl. Open een venster met de naam DOS, ga naar de map waarin het vorige script staat en voer het uit:

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

8.1.6. Vbscript, Javascript, Perlscript

Dit zijn scripttalen voor Windows. Ze kunnen in verschillende omgevingen worden uitgevoerd, zoals

  • Windows Scripting Host voor direct gebruik in Windows, met name voor het schrijven van scripts voor systeembeheer
  • Internet Explorer. Het wordt dan gebruikt binnen HTML-pagina’s, waaraan het een zekere mate van interactiviteit toevoegt die onmogelijk te bereiken is met alleen de taal HTML.
  • Internet Information Server (IIS), de webserver van Microsoft op NT/2000, en zijn tegenhanger Personal Web Server (PWS) op Win9x. In dit geval wordt VBScript gebruikt voor server-side programmering, een technologie die door Microsoft ASP (Active Server Pages) wordt genoemd.

Het installatiebestand kan worden gedownload via de URL: http://msdn.microsoft.com/scripting en volg de links naar Windows Script. Er worden geïnstalleerd:

  • de Windows Scripting Host-container, waarmee verschillende scripttalen kunnen worden gebruikt, zoals VBScript en JavaScript, maar ook andere talen zoals PerlScript, dat bij Active Perl wordt geleverd.
  • een VBscript-interpreter
  • een JavaScript-interpreter

Laten we een paar snelle tests uitvoeren. Laten we het volgende vbscript-programma schrijven:

' een klasse
class personne
  Dim nom
  Dim age
End class

' aanmaken van een persoonobject
Set p1=new personne
With p1
  .nom="dupont"
  .age=18
End With

' weergave van de eigenschappen van persoon p1
With p1
  wscript.echo "nom=" & .nom
  wscript.echo "age=" & .age
End With

Dit programma maakt gebruik van objecten. Laten we het objets.vbs noemen (de extensie vbs duidt op een VBScript-bestand). Ga naar de map waarin het zich bevindt en voer het uit:

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

Laten we nu het volgende JavaScript-programma schrijven dat gebruikmaakt van arrays:

// tabel in een variant
// lege array
tableau=new Array();
affiche(tableau);
// array groeit dynamisch
for(i=0;i<3;i++){
  tableau.push(i*10);
}
// tabel weergeven
affiche(tableau);
// nogmaals
for(i=3;i<6;i++){
  tableau.push(i*10);
}
affiche(tableau);

// meerdimensionale 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);

// einde
WScript.quit(0);

// ---------------------------------------------------------
function affiche(tableau){
  // tabel weergeven
  for(i=0;i<tableau.length;i++){
    WScript.echo("tableau[" + i + "]=" + tableau[i]);
  }//voor
}//functie

// ---------------------------------------------------------
function affiche2(tableau){
   // tabelweergave
  for(i=0;i<tableau.length;i++){
    for(j=0;j<tableau[i].length;j++){
      WScript.echo("tableau[" + i + "," + j + "]=" + tableau[i][j]);
    }// voor j
  }//voor i
}//functie

Dit programma maakt gebruik van tabellen. Laten we het tableaux.js noemen (het achtervoegsel js duidt op een JavaScript-bestand). Ga naar de map waarin het zich bevindt en voer het uit:

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

Tot slot nog een laatste voorbeeld in Perlscript. Om toegang te krijgen tot Perlscript moet Active Perl geïnstalleerd zijn.

<job id="PERL1">
  <script language="PerlScript">
       # klassieke Perl
    %dico=("maurice"=>"juliette","philippe"=>"marianne");
    @cles= keys %dico;
    for ($i=0;$i<=$#sleutels;$i++){
        $cle=$cles[$i];
      $valeur=$dico{$cle};
        $WScript->echo ("clé=".$cle.", valeur=".$valeur);
    }
     # van het Perl-script dat gebruikmaakt van Windows Script-objecten
    $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>

Dit programma laat zien hoe twee woordenboeken worden aangemaakt en gebruikt: één op de klassieke Perl-manier, de andere met het Scripting Dictionary-object van Windows Script. Laten we deze code opslaan in het bestand dico.wsf (wsf is de extensie van Windows Script-bestanden). Ga naar de map van dit programma en voer het uit:

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 kan gebruikmaken van de objecten uit de container waarin het wordt uitgevoerd. In dit geval waren dat objecten uit de Windows Script-container. In de context van webprogrammering kunnen de scripts VBscript, JavaScript en Perlscript worden uitgevoerd, hetzij binnen de browser IE, hetzij op een server PWS of IIS. Als het script enigszins complex is, kan het verstandig zijn om het buiten de webcontext te testen, binnen de Windows Script-container zoals eerder besproken. Op deze manier kunnen alleen de functies van het script worden getest die geen gebruik maken van objecten die specifiek zijn voor de browser of de server. Zelfs met deze beperking blijft deze mogelijkheid interessant, omdat het over het algemeen vrij onpraktisch is om scripts te debuggen die binnen webservers of browsers worden uitgevoerd.

8.1.7. JAVA

Java is beschikbaar op URL: http://www.sun.com en wordt geïnstalleerd in een mappenstructuur die we <java> zullen noemen en die de volgende elementen bevat:

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

In de map 'bin' vindt u javac.exe, de Java-compiler, en java.exe, de Java Virtual Machine. U kunt de volgende tests uitvoeren:

  1. Schrijf het volgende script:
//Java-programma dat de tijd weergeeft

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

public class heure{
  public static void main(String arg[]){
     // datum en tijd ophalen
     Date maintenant=new Date();
      // we geven weer
     System.out.println("Il est "+maintenant.getHours()+
        ":"+maintenant.getMinutes()+":"+maintenant.getSeconds());
  }//main
}//klasse
  1. Sla dit programma op onder de naam heure.java. Open een venster met de naam DOS. Ga naar de map waarin het bestand heure.java staat en compileer het:
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 het bovenstaande commando moet c:\jdk1.3\bin\javac worden vervangen door het exacte pad naar de compiler javac.exe. In dezelfde map als heure.java moet u een bestand heure.class vinden; dit is het programma dat nu door de virtuele machine java.exe zal worden uitgevoerd.

  1. Voer het programma uit:
D:\data\java\essais>c:\jdk1.3\bin\java heure
Il est 10:44:2

8.1.8. Apache-server

We hebben gezien dat de Apache-server verkregen kan worden via de toepassing EasyPhp. Om deze rechtstreeks te verkrijgen, gaan we naar de website van Apache: http://www.apache.org. Tijdens de installatie wordt een mappenstructuur aangemaakt waarin alle benodigde bestanden voor de server te vinden zijn. Laten we deze map <apache> noemen. Deze bevat een mappenstructuur die er ongeveer als volgt uitziet:

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
map met Apache-configuratiebestanden
logs
map met Apache-logbestanden (monitoring)
bin
de uitvoerbare bestanden van Apache

8.1.8.1. Configuration

In de map <Apache>\conf bevinden zich de volgende bestanden: httpd.conf, srm.conf, access.conf. In de nieuwste versies van Apache zijn de drie bestanden samengevoegd in httpd.conf. We hebben de belangrijkste punten van dit configuratiebestand al besproken. In de volgende voorbeelden is de Apache-versie van EasyPhp gebruikt voor de tests en dus ook het bijbehorende configuratiebestand. Daarin is DocumentRoot, dat de root van de webpagina-structuur aangeeft, e:\program files\easyphp\www.

Maak ter test het bestand intro.php aan met alleen de volgende regel:

<? phpinfo() ?>

en plaats het in de hoofdmap van de Apache-server (DocumentRoot hierboven). Roep de pagina URL op via http://localhost/intro.php. Er zou een lijst met informatie moeten verschijnen:

Image

Het volgende script PHP geeft de tijd weer. We zijn dit al eerder tegengekomen:

<?php
   // tijd: aantal milliseconden sinds 01/01/1970
   // "weergaveformaat datum-tijd
   // d: dag in twee cijfers
   // m: maand (2 cijfers)
   // y: jaar (2 cijfers)
   // H: uur 0,23
   // i: minuten
   // s: seconden
  print "Nous sommes le " . date("d/m/y H:i:s",time());
?>

Plaats dit tekstbestand in de hoofdmap van de Apache-server (DocumentRoot) en noem het date.php. Laten we met een browser de pagina URL http://localhost/date.php opvragen. We krijgen dan de volgende pagina te zien:

Image

Dit wordt gerealiseerd via een regel in de vorm: ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/" in het bestand <apache>\conf\httpd.conf. De syntaxis is ScriptAlias /cgi-bin/ "<cgi-bin>", waarbij <cgi-bin> de map is waarin CGI-scripts kunnen worden geplaatst. CGI (Common Gateway Interface) is een standaard voor de communicatie tussen de WEB-server en applicaties. Een client vraagt de webserver om een dynamische pagina, c.a.d, een pagina die door een programma wordt gegenereerd. De server WEB moet dus een programma vragen om de pagina te genereren. CGI definieert de communicatie tussen de server en het programma, met name de wijze waarop informatie tussen deze twee entiteiten wordt overgedragen.

Wijzig indien nodig de regel ScriptAlias /cgi-bin/ "<cgi-bin>" en start de Apache-server opnieuw op. Voer vervolgens de volgende test uit:

  1. Schrijf het script:
#!c:\perl\bin\perl.exe

# script PERL dat de tijd weergeeft

# modules
use strict;

# programma
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. Plaats dit script in <cgi-bin>\heure.pl, waarbij <cgi-bin> de map is waarin CGI-scripts kunnen worden opgeslagen (zie httpd.conf). De eerste regel #!c:\perl\bin\perl.exe geeft het pad aan naar het uitvoerbare bestand perl.exe. Pas dit indien nodig aan.
  2. Start Apache op als dat nog niet is gebeurd
  3. Roep met een browser het bestand URL op via http://localhost/cgi-bin/heure.pl. Je krijgt dan de volgende pagina te zien:

Image

8.1.9. De server PWS

8.1.9.1. Installation

De server PWS (Personal Web Server) is een persoonlijke versie van de server IIS (Internet Information Server) van Microsoft. Deze laatste is beschikbaar op NT- en 2000-computers. Op Win9x-computers is PWS normaal gesproken beschikbaar via het installatiepakket van Internet Explorer. Het wordt echter niet standaard geïnstalleerd. U moet een aangepaste installatie van IE uitvoeren en aangeven dat PWS moet worden geïnstalleerd. Het is overigens ook beschikbaar in het NT 4.0 Option Pack voor Windows 95.

8.1.9.2. Eerste tests

De basismap van de webpagina’s op de server PWS is drive:\inetpub\wwwroot, waarbij drive de schijf is waarop u PWS hebt geïnstalleerd. We gaan er hierna vanuit dat dit station D is. De URL http://machine/rep1/page1.html komt dus overeen met het bestand d:\inetpub\wwwroot\rep1\page1.html. De PWS-server interpreteert elk bestand met de extensie .asp (Active Server Pages) als een script dat hij moet uitvoeren om een HTML-pagina te genereren.

PWS werkt standaard op poort 80. De Apache-webserver ook... U moet Apache dus stoppen om met PWS te kunnen werken als u beide servers hebt. De andere oplossing is om Apache zo te configureren dat het op een andere poort draait. In het Apache-configuratiebestand httpd.conf vervangt u de regel Port 80 door Port 81. Apache draait dan voortaan op poort 81 en kan tegelijkertijd met PWS worden gebruikt. Als PWS is gestart en je de URL URL http://localhost opvraagt, krijg je een pagina die er ongeveer zo uitziet:

Image

  1. Hieronder vindt u een .reg-bestand om het register aan te passen. Dubbelklik op dit bestand om het register te wijzigen. Hier bevindt de benodigde dll zich in d:\php4 samen met het uitvoerbare PHP-bestand. Pas dit indien nodig aan. De \-tekens moeten in het pad naar de DLL worden verdubbeld.
REGEDIT4

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w3svc\parameters\Script Map]
".php"="d:\\php4\\php4isapi.dll"
  1. Start de machine opnieuw op zodat de wijziging in het register wordt doorgevoerd.
  1. Maak een php-map aan in d:\inetpub\wwwroot, de hoofdmap van de server PWS. Activeer vervolgens PWS en ga naar het tabblad 'Geavanceerd'. Klik op de knop ‘Toevoegen’ om een virtuele map aan te maken:
Répertoire/Parcourir : d:\inetpub\wwwroot\php
Alias : php
Cocher la case exécuter.
  1. Bevestig alles en start PWS opnieuw op. Plaats in d:\inetpub\wwwroot\php het bestand intro.php met uitsluitend de volgende regel:
<? phpinfo() ?>
  1. Vraag de server PWS om het bestand URL http://localhost/php/intro.php. U zou nu de lijst met PHP-informatie moeten zien die al met Apache wordt weergegeven.

8.1.10. Tomcat: Java-servlets en JSP-pagina’s (Java Server Pages)

Tomcat is een webserver waarmee HTML-pagina’s kunnen worden gegenereerd met behulp van servlets (Java-programma’s die door de webserver worden uitgevoerd) of JSP-pagina’s (Java Server Pages), pagina’s waarin Java-code en HTML-code worden gecombineerd. Dit is het equivalent van de ASP-pagina’s (Active Server Pages) van de IIS/PWS-server van Microsoft, waarbij VBScript-code of JavaScript wordt gecombineerd met HTML-code.

8.1.10.1. Installation

Tomcat is beschikbaar op URL: http://jakarta.apache.org. Je downloadt een .exe-installatiebestand. Wanneer je dit programma start, geeft het eerst aan welke JDK het gaat gebruiken. Tomcat heeft namelijk een JDK nodig om zichzelf te installeren en vervolgens de Java-servlets te compileren en uit te voeren. U moet dus een Java-JDK hebben geïnstalleerd voordat u Tomcat installeert. De meest recente JD wordt aanbevolen. De installatie maakt een <tomcat>-mappenstructuur aan:

Image

Dit houdt simpelweg in dat u dit archief in een map uitpakt. Kies een map waarvan het pad alleen namen zonder spaties bevat (bijvoorbeeld niet "Program Files"), omdat er een bug zit in het installatieproces van Tomcat. Kies bijvoorbeeld C:\tomcat of D:\tomcat. Laten we deze map <tomcat> noemen. Daarin bevindt zich een map met de naam jakarta-tomcat en daarin de volgende mapstructuur:

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. De Tomcat-webserver starten/stoppen

Tomcat is een webserver, net als Apache of PWS. Om deze te starten, zijn er snelkoppelingen beschikbaar in het programmamenu:

Start Tomcat
om Tomcat te starten
Stop Tomcat
om Tomcat te stoppen

Wanneer je Tomcat start, verschijnt er een DOS-venster met de volgende inhoud:

Image

Je kunt dit DOS-venster minimaliseren. Het blijft zichtbaar zolang Tomcat actief is. Vervolgens kun je de eerste tests uitvoeren. De Tomcat-webserver draait op poort 8080. Zodra Tomcat is gestart, open je een webbrowser en ga je naar http://localhost:8080. Je zou de volgende pagina moeten zien:

Image

Volg de link Servlet Examples:

Image

Klik op de link Execute van RequestParameters en vervolgens op die van Source. Zo krijgt u een eerste indruk van wat een Java-servlet is. U kunt hetzelfde doen met de links op de pagina's JSP.

Om Tomcat te stoppen, gebruik je de link ‘Stop Tomcat’ in het programmamenu.

8.1.11. JBuilder

JBuilder is een ontwikkelomgeving voor Java-toepassingen. Voor het bouwen van Java-servlets zonder grafische interfaces is een dergelijke omgeving niet strikt noodzakelijk. Een teksteditor en een JDK volstaan. Alleen biedt JBuilder enkele extra voordelen ten opzichte van de vorige methode:

  • gemak bij het debuggen: de compiler geeft aan welke regels in een programma fouten bevatten en het is eenvoudig om daar naartoe te gaan
  • codesuggesties: wanneer je een Java-object gebruikt, geeft JBuilder direct de lijst met eigenschappen en methoden ervan weer. Dit is erg handig, aangezien de meeste Java-objecten zeer veel eigenschappen en methoden hebben die moeilijk te onthouden zijn.

JBuilder is te vinden op de website http://www.borland.com/jbuilder. Je moet een formulier invullen om de software te verkrijgen. Een activeringscode wordt per e-mail verzonden. Om JBuilder 7 te installeren, is bijvoorbeeld als volgt te werk gegaan:

  • er werden drie zip-bestanden gedownload: voor de applicatie, voor de documentatie en voor de voorbeelden. Elk van deze zip-bestanden heeft een aparte link op de website van JBuilder.
  • Eerst werd de applicatie geïnstalleerd, daarna de documentatie en ten slotte de voorbeelden
  • Wanneer u de applicatie voor het eerst start, wordt om een activeringssleutel gevraagd: dit is de sleutel die u per e-mail hebt ontvangen. In versie 7 bestaat deze sleutel in feite uit een volledig tekstbestand dat u bijvoorbeeld in de installatiemap van JB7 kunt plaatsen. Op het moment dat om de sleutel wordt gevraagd, wijst u het betreffende bestand aan. Zodra dit is gebeurd, wordt de sleutel niet meer gevraagd.

Er zijn enkele nuttige instellingen die u moet uitvoeren als u JBuilder wilt gebruiken om Java-servlets te bouwen. De zogenaamde ‘Jbuilder Personal’-versie is namelijk een vereenvoudigde versie die met name niet alle klassen bevat die nodig zijn voor webontwikkeling in Java. Je kunt ervoor zorgen dat JBuilder gebruikmaakt van de klassenbibliotheken die door Tomcat worden geleverd. Dit doe je als volgt:

  • start JBuilder

Image

  • schakel de optie Tools/Configure JDKs in

Image

In het gedeelte ‘JDK Settings’ hierboven staat normaal gesproken in het veld ‘Name’ een JDK 1.3.1. Als u een recentere versie van JDK hebt, gebruikt u de knop ‘Change’ om de installatiemap van deze versie aan te geven. Hierboven is de map E:\Program Files\jdk14 opgegeven, waarin een JDK 1.4 was geïnstalleerd. Voortaan zal JBuilder deze JDK gebruiken voor zijn compilaties en uitvoeringen. In het gedeelte (Class, Source, Documentation) staat de lijst met alle klassenbibliotheken die door JBuilder zullen worden doorzocht, in dit geval de klassen van JDK 1.4. De klassen hiervan zijn niet voldoende om webontwikkeling in Java te doen. Om andere klassenbibliotheken toe te voegen, gebruik je de knop ‘Add’ en selecteer je de extra .jar-bestanden die je wilt gebruiken. De .jar-bestanden zijn klassenbibliotheken. Tomcat 4.x bevat alle klassenbibliotheken die nodig zijn voor webontwikkeling. Deze bevinden zich in <tomcat>\common\lib, waarbij <tomcat> de installatiemap van Tomcat is:

Image

Met de knop Add voegen we deze bibliotheken één voor één toe aan de lijst met bibliotheken die door JBuilder worden doorzocht:

Image

Vanaf nu kunnen we Java-programma’s compileren die voldoen aan de J2EE-standaard, met name Java-servlets. JBuilder dient alleen voor het compileren; de uitvoering wordt later door Tomcat verzorgd volgens de procedures die in de cursus worden uitgelegd.

8.2. Broncode van programma’s

8.2.1. De generieke client TCP

Veel diensten die in de beginjaren van het internet zijn ontstaan, werken volgens het eerder besproken echo-servermodel: de communicatie tussen client en server verloopt via de uitwisseling van tekstregels. We gaan een generieke TCP-client schrijven die als volgt wordt gestart: java cltTCPgenerique server poort

Deze client TCP maakt verbinding met poort port van de server serveur. Vervolgens maakt hij twee threads aan:

  1. een thread die de op het toetsenbord ingevoerde opdrachten leest en deze naar de server verstuurt
  2. een thread die de antwoorden van de server leest en deze op het scherm weergeeft

Waarom twee threads? Elke TCP-IP-service heeft zijn eigen specifieke protocol en soms doen zich de volgende situaties voor:

  • de client moet meerdere regels tekst verzenden voordat hij een antwoord krijgt
  • het antwoord van een server kan uit meerdere regels tekst bestaan

Daarom is de lus waarbij één regel naar de server wordt verzonden en vervolgens één regel van de server wordt ontvangen, niet altijd geschikt. We gaan daarom twee afzonderlijke lussen maken:

  • een lus voor het lezen van de op het toetsenbord ingevoerde opdrachten die naar de server moeten worden verzonden. De gebruiker geeft het einde van de opdrachten aan met het trefwoord fin.
  • een lus voor het ontvangen en weergeven van de antwoorden van de server. Dit wordt een oneindige lus die alleen wordt onderbroken wanneer de netwerkstroming door de server wordt gesloten of wanneer de gebruiker via het toetsenbord het commando fin invoert.

Om deze twee lussen van elkaar te scheiden, hebben we twee onafhankelijke threads nodig. Laten we een uitvoervoorbeeld bekijken waarin onze generieke TCP-client verbinding maakt met een dienst SMTP (SendMail Transfer Protocol). Deze dienst is verantwoordelijk voor het doorsturen van e-mail naar de ontvangers. Hij draait op poort 25 en maakt gebruik van een communicatieprotocol waarbij tekstregels worden uitgewisseld.

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]

Laten we deze client-server-uitwisselingen eens bekijken:

  • de service SMTP verstuurt een welkomstbericht wanneer een client verbinding maakt:
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
  • sommige services hebben een commando help dat informatie geeft over de commando's die met de service kunnen worden gebruikt. Hier is dat niet het geval. De commando's SMTP die in het voorbeeld worden gebruikt, zijn de volgende:
    • mail from: expéditeur, om het e-mailadres van de afzender van het bericht aan te geven
    • rcpt to: destinataire, om het e-mailadres van de ontvanger van het bericht aan te geven. Als er meerdere ontvangers zijn, wordt het commando rcpt to: zo vaak als nodig is herhaald voor elke ontvanger.
    • data, waarmee aan de server SMTP wordt aangegeven dat het bericht wordt verzonden. Zoals aangegeven in het antwoord van de server, bestaat dit bericht uit een reeks regels die eindigt met een regel die uitsluitend uit een punt bestaat. Een bericht kan headers bevatten die door een lege regel van de hoofdtekst worden gescheiden. In ons voorbeeld hebben we een onderwerp opgegeven met het trefwoord Subject:
  • zodra het bericht is verzonden, kan men de server laten weten dat men klaar is met het commando quit. De server verbreekt dan de netwerkverbinding. De leesthread kan deze gebeurtenis detecteren en stoppen.
  • De gebruiker typt vervolgens ‘fin’ op het toetsenbord om ook de thread die de ingevoerde opdrachten leest, te stoppen.

Als we de ontvangen e-mail controleren, zien we het volgende (Outlook):

Image

Merk op dat de dienst SMTP niet kan detecteren of een afzender geldig is of niet. Daarom kun je het veld from van een bericht nooit vertrouwen. In dit geval bestond de afzender machin@univ-angers.fr niet.

Met deze generieke TCP-client kunnen we het communicatieprotocol van internetdiensten achterhalen en op basis daarvan gespecialiseerde klassen bouwen voor clients van deze diensten. Laten we het communicatieprotocol van de dienst POP (Post Office Protocol) onderzoeken, waarmee e-mails die op een server zijn opgeslagen, kunnen worden opgehaald. Deze dienst werkt op poort 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]

De belangrijkste commando's zijn de volgende:

  • user login, waarbij je je login opgeeft op de machine waarop je e-mails staan
  • pass password, waarbij je het wachtwoord opgeeft dat bij de vorige gebruikersnaam hoort
  • list, om de lijst met berichten te krijgen in de vorm van nummer en grootte in bytes
  • retr i, om bericht nr. i te lezen
  • quit, om de dialoog te beëindigen.

Laten we nu eens kijken naar het communicatieprotocol tussen een client en een webserver, die doorgaans op poort 80 draait:

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]

Een webclient stuurt zijn opdrachten naar de server volgens het volgende schema:

commande1
commande2
...
commanden
[ligne vide]

Pas nadat de lege regel is ontvangen, reageert de webserver. In het voorbeeld hebben we slechts één commando gebruikt:

GET /index.html HTTP/1.0

waarmee de server wordt gevraagd om URL /index.html en wordt aangegeven dat er wordt gewerkt met het protocol HTTP versie 1.0. De meest recente versie van dit protocol is 1.1. Het voorbeeld laat zien dat de server heeft gereageerd door de inhoud van het bestand index.html terug te sturen en vervolgens de verbinding heeft verbroken, aangezien we zien dat de thread voor het lezen van de antwoorden is beëindigd. Voordat de inhoud van het bestand index.html werd verzonden, heeft de webserver een reeks headers verzonden, afgesloten met een lege regel:

<-- 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>

De regel <html> is de eerste regel van het bestand /index.html. Het bovenstaande wordt HTTP-headers genoemd (HyperText Transfer Protocol). We gaan hier niet in detail op deze headers ingaan, maar onthoud dat onze generieke client hier toegang toe biedt, wat nuttig kan zijn om ze te begrijpen. De eerste regel bijvoorbeeld:

<-- HTTP/1.1 200 OK

geeft aan dat de benaderde webserver het protocol HTTP/1.1 ondersteunt en dat hij het gevraagde bestand inderdaad heeft gevonden (200 OK), waarbij 200 een HTTP-antwoordcode is. De regels

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

geven de client door dat hij 11251 bytes zal ontvangen die de tekst HTML (HyperText Markup Language) vertegenwoordigen en dat de verbinding aan het einde van de verzending zal worden verbroken.

Dit is dus een erg handige TCP-client. Hij kan ongetwijfeld minder dan het officiële programma telnet, maar het was interessant om hem zelf te schrijven. Het programma van de generieke TCP-client is als volgt:

// geïmporteerde pakketten
import java.io.*;
import java.net.*;

public class clientTCPgenerique{

    // ontvangt als parameter de kenmerken van een dienst in de vorm van
     // serverpoort
     // maakt verbinding met de dienst
     // maakt een thread aan om op het toetsenbord ingevoerde opdrachten te lezen
     // deze worden naar de server verzonden
     // maakt een thread aan om de antwoorden van de server te lezen
     // deze worden op het scherm weergegeven
     // het geheel wordt beëindigd met het commando 'fin' dat via het toetsenbord wordt ingevoerd

   // instantievariabele
  private static Socket client;

    public static void main(String[] args){

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

         // aantal argumenten
        if(args.length != 2)
            erreur(syntaxe,1);

         // de naam van de server wordt genoteerd
        String serveur=args[0];

         // de poort moet een geheel getal >0 zijn
        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;
         // er kunnen problemen optreden
        try{
             // er wordt verbinding gemaakt met de service
            client=new Socket(serveur,port);
        }catch(Exception ex){
             // fout
            erreur("Impossible de se connecter au service ("+ serveur
                +","+port+"), erreur : "+ex.getMessage(),3);
             // einde
            return;
        }//catch

         // de lees- en schrijfthreads worden aangemaakt
    new ClientSend(client).start();
    new ClientReceive(client).start();

         // einde hoofdthread
        return;
    }// main

     // fouten weergeven
    public static void erreur(String msg, int exitCode){
         // fout weergeven
        System.err.println(msg);
         // afsluiten met fout
        System.exit(exitCode);
    }//fout
}//klasse  

class ClientSend extends Thread {
    // klasse die verantwoordelijk is voor het lezen van via het toetsenbord ingevoerde opdrachten
     // en deze via een als parameter doorgegeven TCP-client naar een server te verzenden

    private Socket client;    // de TCP-client

     // constructor
    public ClientSend(Socket client){
         // hier wordt de TCP-client vastgelegd
        this.client=client;
    }//constructor

     // de Run-methode van de thread
    public void run(){

        // lokale gegevens
        PrintWriter OUT=null;            // netwerk-schrijfstroom
    BufferedReader IN=null;        // toetsenbordstroom
        String commande=null;            // op het toetsenbord ingevoerde opdracht

         // foutbeheer
        try{
             // aanmaken van de netwerkschrijfstroom
            OUT=new PrintWriter(client.getOutputStream(),true);
      // aanmaken van de toetsenbordinvoerstroom
      IN=new BufferedReader(new InputStreamReader(System.in));
            // lus voor invoer en verzending van opdrachten
            System.out.println("Commandes : ");
            while(true){
                 // lezen van via het toetsenbord ingevoerde opdracht
                commande=IN.readLine().trim();
                 // klaar?
                if (commande.toLowerCase().equals("fin")) break;
                // commando naar de server verzenden
                OUT.println(commande);
                 // volgend commando
            }//while
        }catch(Exception ex){
             // fout
            System.err.println("Envoi : L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // einde - de streams worden gesloten
        try{
            OUT.close();client.close();
        }catch(Exception ex){}
         // het einde van de thread wordt gemeld
        System.out.println("[Envoi : fin du thread d'envoi des commandes au serveur]");
    }//run
}//klasse

class ClientReceive extends Thread{
    // klasse die verantwoordelijk is voor het lezen van de tekstregels bestemd voor een 
     // TCP-client die als parameter is doorgegeven

    private Socket client;    // de TCP-client

     // constructor
    public ClientReceive(Socket client){
         // de TCP-client wordt geregistreerd
        this.client=client;
    }//constructor

     // Run-methode van de thread
    public void run(){

        // lokale gegevens
        BufferedReader IN=null;        // netwerkleesstroom
        String réponse=null;        // serverantwoord

         // foutbeheer
        try{
             // aanmaken van de netwerkleesstroom
            IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
            // lus voor het lezen van tekstregels uit de stream IN
            while(true){
                 // netwerkstream lezen
                réponse=IN.readLine();
                 // stream gesloten?
                if(réponse==null) break;
                // weergave
                System.out.println("<-- "+réponse);
            }//while
        }catch(Exception ex){
            // fout
            System.err.println("Réception : L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // einde – de streams worden gesloten
        try{
            IN.close();client.close();
        }catch(Exception ex){}
         // het einde van de thread wordt gemeld
        System.out.println("[Réception : fin du thread de lecture des réponses du serveur]");
    }//uitvoeren
}//klasse

8.2.2. De generieke TCP-server

Nu richten we ons op een server

  • die de door zijn clients verzonden commando's op het scherm weergeeft
  • en als antwoord de tekstregels terugstuurt die door een gebruiker via het toetsenbord zijn ingevoerd. Het is dus de gebruiker die als server fungeert.

Het programma wordt gestart met: java serveurTCPgenerique portEcoute, waarbij portEcoute de poort is waarop de clients verbinding moeten maken. De dienstverlening aan de client wordt verzorgd door twee threads:

  • een thread die zich uitsluitend bezighoudt met het lezen van de door de client verzonden tekstregels
  • een thread die zich uitsluitend bezighoudt met het lezen van de antwoorden die de gebruiker via het toetsenbord invoert. Deze thread geeft met het commando `fin` aan dat de verbinding met de client wordt beëindigd.

De server maakt twee threads per klant aan. Als er n klanten zijn, zullen er 2n threads tegelijkertijd actief zijn. De server stopt zelf nooit, tenzij de gebruiker op het toetsenbord op Ctrl-C drukt. Laten we enkele voorbeelden bekijken.

De server wordt gestart op poort 100 en we gebruiken de generieke client om met de server te communiceren. Het venster van de client ziet er als volgt uit:

E:\data\serge\MSNET\c#\netwerk\generieke 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]

De regels die beginnen met <-- zijn de regels die van de server naar de client worden verzonden, de andere zijn de regels van de client naar de server. Het servervenster ziet er als volgt uit:


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]

De regels die beginnen met <-- zijn de regels die van de client naar de server zijn verzonden. De regels N: zijn de regels die van de server naar client nr. N zijn verzonden. De bovenstaande server is nog steeds actief, terwijl client 1 is beëindigd. We starten een tweede client voor dezelfde 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]

Het servervenster ziet er dan als volgt uit:


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

Laten we nu een webserver simuleren door onze generieke server op poort 88 te starten:


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

Laten we nu een browser openen en de pagina URL http://localhost:88/exemple.html opvragen. De browser maakt vervolgens verbinding met poort 88 van de machine localhost en vraagt vervolgens de pagina /exemple.html op:

Image

Laten we nu eens kijken naar het venster van onze server:

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
<--

Zo ontdekken we de headers HTTP die door de browser worden verzonden. Hierdoor kunnen we het protocol HTTP beetje bij beetje ontrafelen. In een eerder voorbeeld hadden we een webclient gemaakt die slechts één commando, namelijk GET, verstuurde. Dat was toen voldoende. We zien hier dat de browser nog andere informatie naar de server stuurt. Deze informatie is bedoeld om de server te laten weten met welk type client hij te maken heeft. We zien ook dat de headers HTTP eindigen met een lege regel.

Laten we een antwoord voor onze client opstellen. De gebruiker achter het toetsenbord is hier de echte server en kan met de hand een antwoord opstellen. Laten we ons het antwoord van een webserver in een eerder voorbeeld nog eens in herinnering brengen:

<-- 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>

Laten we eens proberen een soortgelijk antwoord te geven:

...
<-- 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]

Regels die beginnen met 2: worden vanaf de server naar client nr. 2 verzonden. Het commando fin verbreekt de verbinding tussen de server en de client. In ons antwoord hebben we ons beperkt tot de volgende HTTP-headers:

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

We geven de bestandsgrootte van het bestand dat we gaan verzenden (Content-Length) niet aan, maar we vermelden alleen dat we de verbinding zullen verbreken (Connection: close) nadat dit bestand is verzonden. Dit is voldoende voor de browser. Zodra de verbinding wordt verbroken, weet de browser dat het antwoord van de server is voltooid en geeft hij de pagina HTML weer die naar hem is verzonden. Deze pagina ziet er als volgt uit:

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>

De gebruiker verbreekt vervolgens de verbinding met de client door het commando fin in te voeren. De browser weet dan dat het antwoord van de server is voltooid en kan het vervolgens weergeven:

Image

Als we hierboven View/Source invoeren om te zien wat de browser heeft ontvangen, krijgen we:

Image

dat wil zeggen precies wat we vanaf de generieke server hebben verzonden.

De code van de generieke TCP-server is als volgt:

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

public class serveurTCPgenerique{

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

    // ontvangt verzoeken van clients via de luisterpoort
     // maakt een thread aan om de verzoeken van de client te lezen
     // deze worden op het scherm weergegeven
     // maakt een thread aan om op het toetsenbord ingevoerde opdrachten te lezen
     // deze worden als antwoord naar de klant verzonden
     // het geheel wordt beëindigd met het commando 'fin' dat via het toetsenbord wordt ingevoerd

    final String syntaxe="Syntaxe : pg port";
   // instantievariabele
         // is er een argument
     if(args.length != 1)
        erreur(syntaxe,1);

         // de poort moet een geheel getal >0 zijn
        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);

     // de luisterdienst wordt aangemaakt
    ServerSocket ecoute=null;
    int nbClients=0;    // aantal verwerkte clients
        try{
             // de service wordt aangemaakt
            ecoute=new ServerSocket(port);
             // opvolging
            System.out.println("Serveur générique lancé sur le port " + port);

             // lus voor klantenservice
            Socket client=null;
            while (true){ // oneindige lus  wordt gestopt met Ctrl-C
                 // wachten op een klant
                client=ecoute.accept();

                 // de service wordt uitgevoerd door afzonderlijke threads
                nbClients++;

                 // de lees-/schrijfthreads worden aangemaakt
        new ServeurSend(client,nbClients).start();
        new ServeurReceive(client,nbClients).start();

                // we gaan weer over tot het afwachten van verzoeken
            }// einde while
        }catch(Exception ex){
             // de fout wordt gemeld
            erreur("L'erreur suivante s'est produite : " + ex.getMessage(),3);
        }//catch
    }// einde main

     // fouten weergeven
    public static void erreur(String msg, int exitCode){
         // fout weergeven
        System.err.println(msg);
         // afsluiten met fout
        System.exit(exitCode);
    }//fout
}//klasse

class ServeurSend extends Thread{
    // klasse die verantwoordelijk is voor het lezen van via het toetsenbord ingevoerde antwoorden
     // en deze via een aan de constructor doorgegeven TCP-client naar een client te verzenden

    Socket client;    // de TCP-client
    int numClient;        // clientnummer

     // constructor
    public ServeurSend(Socket client, int numClient){
         // we noteren de TCP-client
        this.client=client;
         // en het bijbehorende nummer
        this.numClient=numClient;
    }//fabrikant

     // Run-methode van de thread
    public void run(){

        // lokale gegevens
        PrintWriter OUT=null;        // netwerk-schrijfstroom
        String réponse=null;        // van het toetsenbord gelezen antwoord
    BufferedReader IN=null;    // toetsenbordstroom

        // tracking
        System.out.println("Thread de lecture des réponses du serveur au client "+ numClient + " lancé");
         // foutbeheer
        try{
             // aanmaken van de netwerkschrijfstroom
            OUT=new PrintWriter(client.getOutputStream(),true);
      // aanmaken van de toetsenbordstroom
      IN=new BufferedReader(new InputStreamReader(System.in));
            // lus voor invoer en verzending van opdrachten
            while(true){
                 // klantidentificatie
                System.out.print("--> " + numClient + " : ");
                 // uitlezen van het via het toetsenbord ingevoerde antwoord
                réponse=IN.readLine().trim();
                // klaar?
                if (réponse.toLowerCase().equals("fin")) break;
                // antwoord naar de server verzenden
                OUT.println(réponse);
                 // volgend antwoord
            }//while
        }catch(Exception ex){
             // fout
            System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // einde - de streams worden gesloten
        try{
            OUT.close();client.close();
        }catch(Exception ex){}
         // het einde van de thread wordt gemeld
        System.out.println("[fin du Thread de lecture des réponses du serveur au client "+ numClient+ "]");
    }//run
}//klasse

class ServeurReceive extends Thread{
    // klasse die verantwoordelijk is voor het lezen van de naar de server verzonden tekstregels 
     // via een TCP-client die aan de constructor wordt doorgegeven

    Socket client;    // de TCP-client
    int numClient;        // clientnummer

     // constructor
    public ServeurReceive(Socket client, int numClient){
         // de TCP-client wordt genoteerd
        this.client=client;
         // en het nummer ervan
        this.numClient=numClient;
    }//fabrikant

     // Run-methode van de thread
    public void run(){

        // lokale gegevens
        BufferedReader IN=null;        // netwerkleesstroom
        String réponse=null;        // serverantwoord

         // opvolging
        System.out.println("Thread de lecture des demandes du client "+ numClient + " lancé");
         // foutbeheer
        try{
             // aanmaken van de netwerkleesstroom
            IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
            // lus voor het lezen van tekstregels uit de stream IN
            while(true){
                 // netwerkstream lezen
                réponse=IN.readLine();
                 // stream gesloten?
                if(réponse==null) break;
                // weergave
                System.out.println("<-- "+réponse);
            }//while
        }catch(Exception ex){
            // fout
            System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
        }//catch
         // einde  de streams worden gesloten
        try{
            IN.close();client.close();
        }catch(Exception ex){}
         // het einde van de thread wordt gemeld
        System.out.println("[fin du Thread de lecture des demandes du client "+ numClient+"]");
    }//run
}//klasse

8.3. JAVASCRIPT

In dit deel laten we drie voorbeelden zien van het gebruik van JavaScript in de pagina's WEB. We richten ons op het beheer van formulieren, maar JavaScript kan nog veel meer.

8.3.1. Gegevens uit een formulier ophalen

Het onderstaande voorbeeld laat zien hoe je in de browser de gegevens kunt ophalen die de gebruiker in een formulier heeft ingevoerd. Dit maakt het doorgaans mogelijk om de gegevens voor te bewerken voordat ze naar de server worden verzonden.

8.3.1.1. Het formulier

We hebben een formulier met de meest gangbare componenten en een knop ‘Weergeven’ waarmee de door de gebruiker ingevoerde gegevens kunnen worden weergegeven.

Image

8.3.1.2. De code

<html>

  <head>
    <title>Un formulaire traité par Javascript</title>
    <script language="javascript">
      function afficher(){
         // geeft de gegevens van het formulier weer in een lijst

         // eerst wissen
        effacerInfos();

         // de waarde van de # velden weergeven
        with(document.frmExemple){
           // verborgen veld
          ecrire("champ caché="+cache.value);
           // enkel tekstveld
          ecrire("champ textuel simple="+simple.value);
           // meervoudig tekstveld
          ecrire("champ textuel multiple="+lignes.value);
          // keuzerondjes
          for(i=0;i<radio.length;i++){
            texte="radio["+i+"]="+radio[i].value;
            if(radio[i].checked) texte+=", coché";
            ecrire(texte);
          }//for
             // selectievakjes
          for(i=0;i<qcm.length;i++){
            texte="qcm["+i+"]="+qcm[i].value;
            if(qcm[i].checked) texte+=", coché";
            ecrire(texte);
          }//for
           //vervolgkeuzelijst
          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);
          }//voor
           //meerkeuzelijst
          for(i=0;i<lstVoitures.length;i++){
            texte="lstVoitures["+i+"]="+lstVoitures.options[i].text;
            if(lstVoitures.options[i].selected) texte+=",sélectionné";
            ecrire(texte);
          }//voor
           //wachtwoord
          ecrire("mot de passe="+passwd.value);
        }//met
      }//functie

      function ecrire(texte){
         // tekst schrijven in de informatielijst
        frmInfos.lstInfos.options[frmInfos.lstInfos.length]=new Option(texte);
      }//schrijven

      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. Reguliere expressies in JavaScript

Aan de browserzijde kan JavaScript worden gebruikt om de geldigheid van de door de gebruiker ingevoerde gegevens te controleren voordat deze naar de server worden verzonden. Hieronder vindt u een testprogramma voor deze reguliere expressies.

8.3.2.1. De testpagina

Image

8.3.2.2. De code van de pagina

<html>

  <head>
    <title>Les expressions régulières en Javascript</title>
    <script language="javascript">
      function afficherInfos(){
        with(document.frmRegExp){
           // moet er iets gebeuren?
          if (! verifier()) return;
          // oké – we wissen de vorige resultaten
          effacerInfos();
           // controle van het sjabloon
          modele=new RegExp(txtModele.value);
          champs=modele.exec(txtChaine.value);
          if(champs==null)
             // geen overeenkomst tussen sjabloon en tekenreeks
            ecrireInfos("pas de correspondance");
          else{
             // overeenkomst – de verkregen resultaten worden weergegeven
            ecrireInfos("Il y a correspondance");
            for(i=0;i<champs.length;i++)
              ecrireInfos("champs["+i+"]=["+champs[i]+"]");
          }//anders
        }//met
      }//functie

      function ecrireInfos(texte){
        // tekst schrijven naar de informatielijst
        document.frmRegExp.lstInfos.options[document.frmRegExp.lstInfos.length]=new Option(texte);
      }//schrijven

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

      function jouer(){
         // test het sjabloon tegen de tekenreeks in het gekozen voorbeeld
        with(document.frmRegExp){
          txtModele.value=lstModeles.options[lstModeles.selectedIndex].text
          txtChaine.value=lstChaines.options[lstChaines.selectedIndex].text
          afficherInfos();
        }//met
      }//afspelen

      function ajouter(){
         //voegt de huidige test toe aan de voorbeelden
        with(document.frmRegExp){
          // moet er iets gebeuren?
          if (! verifier()) return;
           // toevoeging
          lstModeles.options[lstModeles.length]=new Option(txtModele.value);
          lstChaines.options[lstChaines.length]=new Option(txtChaine.value);
           // invoer wissen
          txtModele.value="";
          txtChaine.value="";
        }//met
      }//toevoegen

      function verifier(){
         // controleer of de invoervelden niet leeg zijn
        with(document.frmRegExp){
          champs=/^\s*$/.exec(txtModele.value);
          if(champs!=null){
            alert("Vous n'avez pas indiqué de modèle");
            txtModele.focus();
            return false;
          }//als
          champs=/^\s*$/.exec(txtChaine.value);
          if(champs!=null){
            alert("Vous n'avez pas indiqué de chaîne de test");
            txtChaine.focus();
            return false;
          }//als
           // het is in orde
          return true;
        }//met
      }//controleren
    </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. Lijstbeheer in JavaScript

8.3.3.1. Het formulier

Image

8.3.3.2. De code

<html>

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

    <script language="javascript">
       // toevoegen
      function ajouter(L1,L2,T){
         // voeg de waarde van veld T toe aan de lijsten L1, L2
           // moet er iets gebeuren?
          champs=/^\s*$/.exec(T.value);
          if(champs!=null){
            // het veld is leeg
            alert("Vous n'avez pas indiqué la valeur à ajouter");
            txtElement.focus();
            return;
          }//if
           // dan wordt het element toegevoegd
          L1.options[L1.length]=new Option(T.value);
          L2.options[L2.length]=new Option(T.value);
          T.value="";
      }//toevoegen

       //leegmaken
      function vider(L){
         // maakt de lijst L leeg
        L.length=0;
      }//leegmaken

      //overzetten
      function transfert(L1,L2,simple){
        //zet de geselecteerde items uit de lijst L1 over naar L2

         // iets te doen?
         // index van het geselecteerde element in L1
        index1=L1.selectedIndex;
        if(index1==-1){
          alert("Vous n'avez pas sélectionné d'élément");
          return;
        }//if
         // wat is de selectiemodus voor de elementen in de lijsten
        if(simple){ // enkele selectie
          element1=L1.options[index1].text;
           //toevoegen in L2
          L2.options[L2.length]=new Option(element1);
          //verwijderen in L1
          L1.options[index1]=null;
        }//enkelvoudig
        if(! simple){ //meervoudige selectie
           //lijst 1 in omgekeerde volgorde doorlopen
          for(i=L1.length-1;i>=0;i--){
            //element geselecteerd?
            if(L1.options[i].selected){
               //toevoegen aan L2
              L2.options[L2.length]=new Option(L1.options[i].text);
              //verwijderen uit L1
              L1.options[i]=null;
            }//als
          }//voor i
        }//if ! eenvoudig
      }//overdracht
   </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>