8. Załączniki
8.1. Narzędzia do tworzenia stron internetowych
W tym miejscu wskazujemy, gdzie znaleźć i jak zainstalować narzędzia niezbędne do tworzenia stron internetowych. Niektóre narzędzia przeszły aktualizacje i może się zdarzyć, że podane tutaj wyjaśnienia nie będą już pasowały do najnowszych wersji. W takim przypadku czytelnik będzie musiał dostosować się do sytuacji... W ramach kursu programowania stron internetowych będziemy korzystać głównie z następujących narzędzi, z których wszystkie są dostępne bezpłatnie:
- nową przeglądarkę obsługującą format XML. Przykłady z kursu zostały przetestowane w przeglądarce Internet Explorer 6.
- najnowszy JDK (Java Development Kit). Przykłady z kursu zostały przetestowane z JDK 1.4. Ten JDK zawiera wtyczkę Java 1.4 dla przeglądarek, co pozwala im wyświetlać aplety Java korzystające z JDK 1.4.
- środowisko programistyczne Java do pisania serwletów Java. W tym przypadku jest to JBuilder 7.
- serwery WWW: Apache, PWS (Personal Web Server), Tomcat.
- Apache będzie wykorzystywany do tworzenia aplikacji internetowych w języku PERL (Practical Extracting and Reporting Language) lub PHP (Personal Home Page)
- PWS będzie wykorzystywany do tworzenia aplikacji internetowych w języku ASP (Active Server Pages) lub PHP
- Tomcat będzie wykorzystywany do tworzenia aplikacji internetowych przy użyciu serwletów Java lub stron JSP (Java Server Pages)
- aplikacja do zarządzania bazą danych: MySQL
- EasyPHP: narzędzie łączące serwer WWW Apache, język PHP oraz SGBD MySQL
8.1.1. Serwery WWW, przeglądarki, języki skryptowe
- Główne serwery WWW
- Apache (Linux, Windows)
- Interner Information Server IIS (NT), Personal Web Server PWS (Windows 9x)
- Główne przeglądarki
- Internet Explorer (Windows)
- Netscape (Linux, Windows)
- Języki skryptowe po stronie serwera
- VBScript (IIS, PWS)
- JavaScript (IIS, PWS)
- Perl (Apache, IIS, PWS)
- PHP (Apache, IIS, PWS)
- Java (Apache, Tomcat)
- Języki .NET
- Języki skryptowe po stronie przeglądarki
- VBScript (IE)
- JavaScript (IE, Netscape)
- PerlScript (IE)
- Java (IE, Netscape)
8.1.2. Gdzie znaleźć narzędzia
http://www.netscape.com/ (link do plików do pobrania) | |
http://www.microsoft.com/windows/ie/default.asp | |
http://www.php.net http://www.php.net/downloads.php (pliki binarne dla systemu Windows) | |
http://www.activestate.com http://www.activestate.com/Products/ http://www.activestate.com/Products/ActivePerl/ | |
http://msdn.microsoft.com/scripting (kliknij link „skrypt Windows”) | |
http://java.sun.com/ http://java.sun.com/downloads.html (JSE) http://java.sun.com/j2se/1.4/download.html | |
http://www.apache.org/ http://www.apache.org/dist/httpd/binaries/win32/ | |
zawarte w pakiecie opcjonalnym NT 4.0 dla systemu Windows 95 zawarte w pakiecie CD dla systemu Windows 98 http://www.microsoft.com/ntserver/nts/downloads/recommended/NT4OptPk/win95.asp | |
http://www.microsoft.com | |
http://jakarta.apache.org/tomcat/ | |
http://www.borland.com/jbuilder/ http://www.borland.com/products/downloads/download_jbuilder.html | |
http://www.easyphp.org/ http://www.easyphp.org/telechargements.php3 |
8.1.3. EasyPHP
Ta aplikacja jest bardzo praktyczna, ponieważ w jednym pakiecie zawiera:
- serwer WWW Apache (1.3.x)
- język PHP (4.x)
- SGBD MySQL (3.23.x)
- narzędzie administracyjne o numerze MySQL: PhpMyAdmin
Aplikacja instalacyjna ma następujący wygląd:

Instalacja EasyPHP przebiega bez problemów, a w systemie plików tworzona jest struktura katalogów:

plik wykonywalny aplikacji | |
struktura katalogów serwera Apache | |
struktura katalogów bazy danych MySQL SGBD | |
struktura katalogów aplikacji phpMyAdmin | |
struktura katalogów php | |
katalog główny drzewa stron internetowych dostarczanych przez serwer Apache EasyPHP | |
drzewo katalogów, w którym można umieścić skrypty CGI dla serwera Apache |
Główną zaletą EasyPHP jest to, że aplikacja jest dostarczana w stanie wstępnie skonfigurowanym. Dzięki temu Apache, PHP i MySQL są już skonfigurowane do współpracy. Po uruchomieniu EasyPhp za pomocą skrótu w menu programów w prawym dolnym rogu ekranu pojawia się ikona.
![]() |
To litera „E” z czerwoną kropką powinna migać, jeśli serwer WWW Apache i baza danych MySQL działają prawidłowo. Po kliknięciu na nią prawym przyciskiem myszy pojawiają się opcje menu:

Opcja Administration umożliwia wprowadzanie ustawień i przeprowadzanie testów poprawności działania:

8.1.3.1. Administracja PHP
Przycisk „Informacje o PHP” powinien umożliwić sprawdzenie prawidłowego działania kombinacji Apache-PHP: powinna pojawić się strona informacyjna PHP:

Przycisk „rozszerzenia” wyświetla listę zainstalowanych rozszerzeń dla PHP. Są to w rzeczywistości biblioteki funkcji.

Powyższy ekran pokazuje na przykład, że funkcje niezbędne do korzystania z bazy danych MySQL są rzeczywiście dostępne.
Przycisk „Ustawienia” wyświetla dane administratora bazy danych login/motdepasse.

Korzystanie z bazy danych MySQL wykracza poza zakres tej krótkiej prezentacji, ale jasne jest, że należy ustawić hasło dla administratora bazy danych.
8.1.3.2. Administracja serwerem Apache
Również na stronie administracyjnej EasyPHP link „wasze aliasy” pozwala zdefiniować aliasy powiązane z katalogiem. Umożliwia to umieszczenie stron internetowych w innym miejscu niż katalog www w drzewie katalogów easyPhp.

Jeśli na powyższej stronie wprowadzimy następujące informacje:

i użyjemy przycisku valider, do pliku <easyphp>\apache\conf\httpd.conf zostaną dodane następujące wiersze:
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> oznacza katalog instalacyjny pliku EasyPHP. httpd.conf to plik konfiguracyjny serwera Apache. Można więc osiągnąć ten sam efekt, edytując bezpośrednio ten plik. Zmiany w pliku httpd.conf są zazwyczaj natychmiast uwzględniane przez serwer Apache. Jeśli tak się nie stanie, należy go zatrzymać, a następnie uruchomić ponownie, zawsze za pomocą ikony easyphp:

Aby zakończyć nasz przykład, możemy teraz umieścić strony internetowe w drzewie katalogów e:\data\serge\web:
i wywołać tę stronę, używając aliasu st:

W tym przykładzie serwer Apache został skonfigurowany do pracy na porcie 81. Jego domyślnym portem jest 80. Jest to określone w następującym wierszu pliku httpd.conf, który już wcześniej omówiliśmy:
8.1.3.3. Plik konfiguracyjny serwera Apache htpd.conf
Jeśli chcemy nieco bardziej precyzyjnie skonfigurować serwer Apache, musimy „ręcznie” zmodyfikować jego plik konfiguracyjny httpd.conf, znajdujący się w folderze <easyphp>\apache\conf:

Oto kilka ważnych informacji dotyczących tego pliku konfiguracyjnego:
rola | |
wskazuje folder, w którym znajduje się drzewo katalogów Apache | |
określa, na którym porcie będzie działał serwer WWW. Zazwyczaj jest to port 80. Zmieniając tę linię, można skonfigurować serwer WWW tak, aby działał na innym porcie | |
adres e-mail administratora serwera Apache | |
nazwa komputera, na którym „działa” serwer Apache | |
katalog instalacyjny serwera Apache. Gdy w pliku konfiguracyjnym pojawiają się nazwy plików względne, odnoszą się one do tego katalogu. | |
katalog główny drzewa stron internetowych udostępnianych przez serwer. W tym przypadku adres URL http://machine/rep1/fic1.html będzie odpowiadał plikowi E:\Program Files\EasyPHP\www\rep1\fic1.html | |
ustala właściwości poprzedniego folderu | |
folder logów, a więc w rzeczywistości <ServerRoot>\logs\error.log: E:\Program Files\EasyPHP\apache\logs\error.log. Jest to plik, który należy sprawdzić, jeśli zauważysz, że serwer Apache nie działa. | |
E:\Program Files\EasyPHP\cgi-bin będzie katalogiem głównym drzewa katalogów, w którym można umieszczać skrypty CGI. Zatem adres URL skryptu CGI będzie wyglądał następująco: http://machine/cgi-bin/rep1/script1.pl E:\Program Files\EasyPHP\cgi-bin\rep1\script1.pl. | |
ustala właściwości powyższego folderu | |
wiersze ładujące moduły umożliwiające Apache'owi współpracę z PHP4. | |
określa rozszerzenia plików, które mają być traktowane jako pliki do przetworzenia przez PHP |
8.1.3.4. Zarządzanie MySQL za pomocą PhpMyAdmin
Na stronie administracyjnej EasyPhp należy kliknąć przycisk PhpMyAdmin:

Lista rozwijana pod Accueil pozwala wyświetlić bazy . | ![]() |
Liczba w nawiasie oznacza liczbę tabel. Po wybrano bazę, wyświetlą się zawarte w niej tabele: | ![]() |
Strona internetowa oferuje szereg operacji na bazie danych:

Jeśli klikniemy link Afficher z user:

Jest tu tylko jeden użytkownik: root, który jest administratorem MySQL. Klikając link Modifier, można by zmienić jego hasło, które obecnie jest puste, co nie jest zalecane w przypadku administratora.
Nie będziemy się więcej rozpisywać na temat PhpMyAdmin, które jest bogatym oprogramowaniem i zasługiwałoby na omówienie na kilku stronach.
8.1.4. PHP
Widzieliśmy już, jak uzyskać PHP za pośrednictwem aplikacji EasyPhp. Aby uzyskać PHP bezpośrednio, należy przejść na stronę http://www.php.net.
PHP nie jest przeznaczony wyłącznie do użytku w sieci WWW. Można go wykorzystać jako język skryptowy w systemie Windows. Utwórz poniższy skrypt i zapisz go pod nazwą date.php:
<?
// skrypt PHP wyświetlający godzinę
$maintenant=date("j/m/y, H:i:s",time());
echo "Nous sommes le $maintenant";
?>
W oknie DOS przejdź do katalogu date.php i uruchom go:
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
Najlepiej, aby przeglądarka Internet Explorer była już zainstalowana. Jeśli jest zainstalowana, Active Perl skonfiguruje ją tak, aby akceptowała skrypty PERL na stronach HTML; skrypty te będą wykonywane przez sam program IE po stronie klienta. Strona internetowa Active Perl znajduje się pod adresem URL http://www.activestate.comA. Po zakończeniu instalacji PERL zostanie zainstalowany w katalogu, który nazwiemy <perl>. Zawiera on następującą strukturę katalogów:
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
Plik wykonywalny perl.exe znajduje się w katalogu <perl>\bin. Perl to język skryptowy działający w systemach Windows i Unix. Jest on również wykorzystywany w programowaniu WEB. Napiszmy pierwszy skrypt:
# skrypt PERL wyświetlający godzinę
# moduły
use strict;
# program
my ($secondes,$minutes,$heure)=localtime(time);
print "Il est $heure:$minutes:$secondes\n";
Zapisz ten skrypt w pliku o nazwie heure.pl. Otwórz okno DOS, przejdź do katalogu zawierającego poprzedni skrypt i uruchom go:
8.1.6. Vbscript, Javascript, Perlscript
Języki te są językami skryptowymi dla systemu Windows. Mogą one działać w różnych środowiskach, takich jak
- Windows Scripting Host, umożliwiających bezpośrednie wykorzystanie w systemie Windows, zwłaszcza do pisania skryptów do zarządzania systemem
- Internet Explorer. Jest on wówczas wykorzystywany w ramach stron HTML, którym zapewnia pewną interaktywność niemożliwą do osiągnięcia przy użyciu samego języka HTML.
- Internet Information Server (IIS) – serwer WWW firmy Microsoft w systemie NT/2000 oraz jego odpowiednik Personal Web Server (PWS) w systemie Win9x. W tym przypadku do programowania po stronie serwera internetowego wykorzystuje się VBScript – technologię nazwaną przez firmę Microsoft ASP (Active Server Pages).
Plik instalacyjny można pobrać z serwisu URL: http://msdn.microsoft.com/scripting, a następnie należy postępować zgodnie z linkami dotyczącymi Windows Script. Instalowane są:
- kontener Windows Scripting Host, umożliwiający korzystanie z różnych języków skryptowych, takich jak VBScript i JavaScript, a także innych, np. PerlScript, który jest dostarczany wraz z Active Perl.
- interpreter VBscript
- interpreter JavaScript
Przedstawmy kilka szybkich testów. Stwórzmy następujący program vbscript:
' klasa
class personne
Dim nom
Dim age
End class
' utworzenie obiektu „osoba”
Set p1=new personne
With p1
.nom="dupont"
.age=18
End With
' wyświetlanie właściwości osoby p1
With p1
wscript.echo "nom=" & .nom
wscript.echo "age=" & .age
End With
Ten program wykorzystuje obiekty. Nazwijmy go objets.vbs (rozszerzenie vbs oznacza plik vbscript). Przejdźmy do katalogu, w którym się znajduje, i uruchommy go:
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
Teraz stwórzmy następujący program w języku JavaScript, który wykorzystuje tablice:
// tablica w wariancie
// pusta tablica
tableau=new Array();
affiche(tableau);
// tablica powiększa się dynamicznie
for(i=0;i<3;i++){
tableau.push(i*10);
}
// wyświetlanie tablicy
affiche(tableau);
// jeszcze
for(i=3;i<6;i++){
tableau.push(i*10);
}
affiche(tableau);
// tabele wielowymiarowe
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);
// koniec
WScript.quit(0);
// ---------------------------------------------------------
function affiche(tableau){
// wyświetlanie tabeli
for(i=0;i<tableau.length;i++){
WScript.echo("tableau[" + i + "]=" + tableau[i]);
}//dla
}//funkcja
// ---------------------------------------------------------
function affiche2(tableau){
// wyświetlanie tabeli
for(i=0;i<tableau.length;i++){
for(j=0;j<tableau[i].length;j++){
WScript.echo("tableau[" + i + "," + j + "]=" + tableau[i][j]);
}// dla j
}//dla i
}//funkcja
Ten program wykorzystuje tablice. Nazwijmy go tableaux.js (rozszerzenie „js” oznacza plik JavaScript). Przejdźmy do katalogu, w którym się znajduje, i uruchommy go:
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
Na zakończenie jeszcze jeden przykład w języku Perlscript. Aby uzyskać dostęp do Perlscript, należy zainstalować Active Perl.
<job id="PERL1">
<script language="PerlScript">
# klasycznego Perla
%dico=("maurice"=>"juliette","philippe"=>"marianne");
@cles= keys %dico;
for ($i=0;$i<=$#klucze;$i++){
$cle=$cles[$i];
$valeur=$dico{$cle};
$WScript->echo ("clé=".$cle.", valeur=".$valeur);
}
# skryptu Perla wykorzystującego obiekty Windows Script
$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>
Ten program pokazuje tworzenie i wykorzystanie dwóch słowników: jednego w klasycznym stylu Perla, a drugiego z wykorzystaniem obiektu Scripting Dictionary w Windows Script. Zapiszmy ten kod w pliku dico.wsf (wsf to rozszerzenie plików Windows Script). Przejdźmy do folderu tego programu i uruchommy go:
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 może korzystać z obiektów kontenera, w którym jest uruchamiany. W tym przypadku były to obiekty kontenera Windows Script. W kontekście programowania internetowego skrypty VBscript, JavaScript, Perlscript mogą być uruchamiane albo w przeglądarce IE, albo na serwerze PWS lub IIS. Jeśli skrypt jest nieco złożony, warto przetestować go poza środowiskiem internetowym, w kontenerze Windows Script, jak pokazano wcześniej. W ten sposób można przetestować jedynie te funkcje skryptu, które nie wykorzystują obiektów charakterystycznych dla przeglądarki lub serwera. Nawet przy tym ograniczeniu opcja ta pozostaje interesująca, ponieważ debugowanie skryptów uruchamianych na serwerach internetowych lub w przeglądarkach jest zazwyczaj dość niewygodne.
8.1.7. JAVA
Język Java jest dostępny na stronie URL: http://www.sun.com i instaluje się w drzewie katalogów o nazwie <java>, które zawiera następujące elementy:
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
W katalogu bin znajdziemy plik javac.exe, czyli kompilator Java, oraz plik java.exe, czyli wirtualną maszynę Java. Można przeprowadzić następujące testy:
- Napisać następujący skrypt:
//program w Javie wyświetlający godzinę
import java.io.*;
import java.util.*;
public class heure{
public static void main(String arg[]){
// pobieranie daty i godziny
Date maintenant=new Date();
// wyświetlanie
System.out.println("Il est "+maintenant.getHours()+
":"+maintenant.getMinutes()+":"+maintenant.getSeconds());
}//main
}//klasa
- Zapisz ten program pod nazwą heure.java. Otwórz okno DOS. Przejdź do katalogu, w którym znajduje się plik heure.java, i skompiluj go:
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.
W powyższym poleceniu ścieżkę c:\jdk1.3\bin\javac należy zastąpić dokładną ścieżką do kompilatora javac.exe. W tym samym katalogu co plik heure.java powinien znajdować się plik heure.class, który jest programem, który zostanie teraz uruchomiony przez maszynę wirtualną java.exe.
- Uruchom program:
8.1.8. Serwer Apache
Widzieliśmy już, że serwer Apache można uzyskać za pomocą aplikacji EasyPhp. Aby pobrać go bezpośrednio, należy przejść na stronę Apache: http://www.apache.org. Instalacja tworzy strukturę katalogów, w której znajdują się wszystkie pliki niezbędne do działania serwera. Nazwijmy ten katalog <apache>. Zawiera on strukturę katalogów podobną do poniższej:
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
katalog plików konfiguracyjnych serwera Apache | |
katalog plików logów (monitorowania) serwera Apache | |
pliki wykonywalne serwera Apache |
8.1.8.1. Configuration
W folderze <Apache>\conf znajdują się następujące pliki: httpd.conf, srm.conf, access.conf. W najnowszych wersjach Apache'a te trzy pliki zostały połączone w jeden plik o nazwie httpd.conf. Omówiliśmy już najważniejsze elementy tego pliku konfiguracyjnego. W poniższych przykładach do testów wykorzystano wersję Apache'a o numerze EasyPhp, a zatem również jej plik konfiguracyjny. W tym pliku DocumentRoot, który określa katalog główny drzewa stron internetowych, to e:\program files\easyphp\www.
8.1.8.2. Link do PHP – Apache
Aby przeprowadzić test, utwórz plik o nazwie intro.php zawierający wyłącznie następujący wiersz:
<? phpinfo() ?>
i umieścić go w katalogu głównym serwera Apache (DocumentRoot powyżej). Wywołaj stronę URL pod adresem http://localhost/intro.php. Powinna pojawić się lista informacji php:

Poniższy skrypt PHP wyświetla godzinę. Spotkaliśmy się z nim już wcześniej:
<?php
// czas: liczba milisekund od 01.01.1970
// „format wyświetlania daty i godziny”
// d: dzień (2 cyfry)
// m: miesiąc (2 cyfry)
// y: rok (2 cyfry)
// H: godzina 0,23
// i: minuty
// s: sekundy
print "Nous sommes le " . date("d/m/y H:i:s",time());
?>
Umieśćmy ten plik tekstowy w katalogu głównym serwera Apache (DocumentRoot) i nazwijmy go date.php. W przeglądarce wywołajmy adres http://localhost/date.php z plikiem URL. Otrzymamy następującą stronę:

8.1.8.3. Link PERL-APACHE
Został on utworzony za pomocą wiersza o postaci: ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/" z pliku <apache>\conf\httpd.conf. Jego składnia to ScriptAlias /cgi-bin/ "<cgi-bin>", gdzie <cgi-bin> to folder, w którym można umieścić skrypty CGI. CGI (Common Gateway Interface) to standard komunikacji między serwerem WEB a aplikacjami. Klient żąda od serwera WWW dynamicznej strony, c.a.d, czyli strony wygenerowanej przez program. Serwer WEB musi zatem poprosić program o wygenerowanie strony. CGI definiuje komunikację między serwerem a programem, w szczególności sposób przekazywania informacji między tymi dwoma podmiotami.
W razie potrzeby zmień wiersz ScriptAlias /cgi-bin/ na „<cgi-bin>” i uruchom ponownie serwer Apache. Następnie przeprowadź następujący test:
- Napisz skrypt:
#!c:\perl\bin\perl.exe
# skrypt PERL wyświetlający godzinę
# moduły
use strict;
# program
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
;
- Umieść ten skrypt w katalogu <cgi-bin>\heure.pl, gdzie <cgi-bin> to katalog, w którym mogą znajdować się skrypty CGI (patrz httpd.conf). Pierwszy wiersz #!c:\perl\bin\perl.exe określa ścieżkę do pliku wykonywalnego perl.exe. W razie potrzeby należy go zmodyfikować.
- Uruchom serwer Apache, jeśli jeszcze tego nie zrobiono
- W przeglądarce należy wywołać plik URL pod adresem http://localhost/cgi-bin/heure.pl. Wyświetli się następująca strona:

8.1.9. Serwer PWS
8.1.9.1. Installation
Serwer PWS (Personal Web Server) jest osobistą wersją serwera IIS (Internet Information Server) firmy Microsoft. Ten ostatni jest dostępny na komputerach z systemem NT i 2000. Na komputerach z systemem Win9x serwer PWS jest zazwyczaj dostępny w pakiecie instalacyjnym przeglądarki Internet Explorer. Nie jest on jednak instalowany domyślnie. Należy przeprowadzić instalację niestandardową IE i zaznaczyć opcję instalacji PWS. Jest on również dostępny w pakiecie NT 4.0 Option Pack dla systemu Windows 95.
8.1.9.2. Wstępne testy
Katalogiem głównym stron internetowych serwera PWS jest „dysk:\inetpub\wwwroot”, gdzie „dysk” oznacza dysk, na którym zainstalowano program PWS. W dalszej części zakładamy, że jest to dysk D. Zatem adres URL http://machine/rep1/page1.html będzie odpowiadał plikowi d:\inetpub\wwwroot\rep1\page1.html. Serwer PWS interpretuje każdy plik z rozszerzeniem .asp (Active Server Pages) jako skrypt, który musi wykonać w celu wygenerowania strony HTML.
PWS domyślnie działa na porcie 80. Serwer WWW Apache również... Jeśli więc korzystasz z obu serwerów, musisz zatrzymać Apache, aby móc pracować z PWS. Innym rozwiązaniem jest skonfigurowanie serwera Apache tak, aby działał na innym porcie. W pliku konfiguracyjnym Apache’a o nazwie httpd.conf należy zastąpić wiersz „Port 80” na „Port 81”. Serwer Apache będzie odtąd działał na porcie 81 i będzie można z niego korzystać jednocześnie z PWS. Jeśli uruchomiono PWS, a następnie wywołamy adres http://localhost, wyświetli się strona podobna do poniższej:

8.1.9.3. Link PHP – PWS
- Poniżej znajduje się plik .reg służący do modyfikacji rejestru. Należy dwukrotnie kliknąć ten plik, aby wprowadzić zmiany w rejestrze. W tym przypadku wymagany plik dll znajduje się w pliku d:\php4 wraz z plikiem wykonywalnym php. W razie potrzeby należy wprowadzić zmiany. Znaki \ w ścieżce do biblioteki DLL należy podwoić.
REGEDIT4
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\w3svc\parameters\Script Map]
".php"="d:\\php4\\php4isapi.dll"
- Uruchom ponownie komputer, aby zmiany w rejestrze zostały uwzględnione.
- Utwórz folder php w d:\inetpub\wwwroot, który jest katalogiem głównym serwera PWS. Następnie uruchom PWS i przejdź do zakładki „Zaawansowane”. Kliknij przycisk „Dodaj”, aby utworzyć folder wirtualny:
- Potwierdź zmiany i uruchom ponownie PWS. Umieść w d:\inetpub\wwwroot\php plik intro.php zawierający wyłącznie następujący wiersz:
- Poproś serwer PWS o plik URL http://localhost/php/intro.php. Powinna pojawić się lista informacji PHP już wyświetlanych przez Apache.
8.1.10. Tomcat: serwlety Java i strony JSP (Java Server Pages)
Tomcat to serwer WWW umożliwiający generowanie stron HTML za pomocą serwletów (programów Java uruchamianych przez serwer WWW) oraz stron JSP (Java Server Pages), czyli stron łączących kod Java z kodem HTML. Jest to odpowiednik stron ASP (Active Server Pages) serwera IIS/PWS firmy Microsoft, gdzie łączy się kod VBScript lub JavaScript z kodem HTML.
8.1.10.1. Installation
Tomcat jest dostępny pod adresem URL: http://jakarta.apache.org. Pobieramy plik instalacyjny .exe. Po uruchomieniu programu najpierw pojawia się informacja, jakiej wersji JDK będzie używał. Tomcat potrzebuje bowiem JDK do zainstalowania się, a następnie do kompilacji i uruchamiania serwletów Java. Dlatego przed instalacją Tomcata należy zainstalować wersję Java o numerze JDK. Zalecana jest najnowsza wersja JD. Instalacja utworzy katalog <tomcat>:

polega po prostu na rozpakowaniu tego archiwum do katalogu. Należy wybrać katalog, którego ścieżka zawiera wyłącznie nazwy bez spacji (na przykład nie „Program Files”), ponieważ w procesie instalacji Tomcata występuje błąd. Można na przykład wybrać C:\tomcat lub D:\tomcat. Nazwijmy ten katalog <tomcat>. Znajdziemy w nim folder o nazwie jakarta-tomcat, a w nim następującą strukturę katalogów:
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. Uruchamianie/wyłączanie serwera WWW Tomcat
Tomcat to serwer WWW, podobnie jak Apache czy PWS. Aby go uruchomić, należy skorzystać z linków dostępnych w menu programów:
aby uruchomić Tomcat | |
do jego wyłączenia |
Po uruchomieniu Tomcata pojawia się okno DOS z następującą treścią:

Okno DOS-a można zminimalizować. Będzie ono widoczne tak długo, jak długo Tomcat będzie aktywny. Następnie można przejść do pierwszych testów. Serwer WWW Tomcat działa na porcie 8080. Po uruchomieniu Tomcata należy otworzyć przeglądarkę internetową i wpisać adres http://localhost:8080. Powinna pojawić się następująca strona:

Kliknij link „Servlet Examples”:

Kliknij link Execute z RequestParameters, a następnie link z Source. Otrzymasz wstępny wgląd w to, czym jest serwlet Java. To samo możesz zrobić, korzystając z linków na stronach JSP.
Aby zatrzymać Tomcat, należy użyć linku „Stop Tomcat” w menu programów.
8.1.11. JBuilder
JBuilder to środowisko programistyczne do tworzenia aplikacji Java. Do tworzenia serwletów Java, w których nie ma interfejsów graficznych, posiadanie takiego środowiska nie jest konieczne. Wystarczy edytor tekstu i JDK. Jednak JBuilder oferuje kilka dodatkowych zalet w porównaniu z poprzednią metodą:
- łatwość debugowania: kompilator sygnalizuje błędne linie w programie i łatwo jest do nich przejść
- sugestie kodu: podczas korzystania z obiektu Java, JBuilder wyświetla na bieżąco listę jego właściwości i metod. Jest to bardzo przydatne, biorąc pod uwagę, że większość obiektów Java posiada bardzo wiele właściwości i metod, które trudno zapamiętać.
JBuilder można znaleźć na stronie http://www.borland.com/jbuilder. Aby uzyskać oprogramowanie, należy wypełnić formularz. Klucz aktywacyjny jest wysyłany pocztą elektroniczną. Aby zainstalować JBuilder 7, postępowano na przykład w następujący sposób:
- pobrano trzy pliki ZIP: z aplikacją, dokumentacją oraz przykładami. Każdy z tych plików ZIP ma osobny link na stronie JBuilder.
- Najpierw zainstalowano aplikację, następnie dokumentację, a na końcu przykłady
- przy pierwszym uruchomieniu aplikacji wymagany jest klucz aktywacyjny: jest to klucz, który został Państwu przesłany pocztą elektroniczną. W wersji 7 klucz ten stanowi w rzeczywistości całą treść pliku tekstowego, który można umieścić na przykład w folderze instalacyjnym JB7. W momencie pojawienia się prośby o klucz należy wskazać ten plik. Po wykonaniu tej czynności klucz nie będzie już ponownie wymagany.
Aby korzystać z programu JBuilder do tworzenia serwletów Java, należy wprowadzić kilka przydatnych ustawień. Wersja zwana „Jbuilder personal” jest bowiem wersją okrojoną, która nie zawiera wszystkich klas niezbędnych do tworzenia aplikacji internetowych w języku Java. Można skonfigurować JBuilder tak, aby korzystał z bibliotek klas dostarczanych przez Tomcat. Należy postępować w następujący sposób:
- uruchom JBuilder

- włączyć opcję Tools/Configure JDKs

W sekcji „JDK Settings” powyżej w polu „Name” zwykle widnieje wartość „JDK 1.3.1”. Jeśli posiadasz nowszą wersję JDK, użyj przycisku „Change”, aby wskazać katalog instalacyjny tej wersji. Powyżej wskazano katalog E:\Program Files\jdk14, w którym zainstalowano wersję JDK 1.4. Od tej pory JBuilder będzie korzystać z tej wersji JDK do kompilacji i uruchamiania. W sekcji (Class, Source, Documentation) znajduje się lista wszystkich bibliotek klas, które będą przeszukiwane przez JBuilder – w tym przypadku są to klasy z JDK 1.4. Klasy z tej biblioteki nie wystarczają do tworzenia aplikacji internetowych w Javie. Aby dodać kolejne biblioteki klas, należy użyć przycisku „Add” i wskazać dodatkowe pliki .jar, z których chcemy korzystać. Pliki .jar to biblioteki klas. Tomcat 4.x zawiera wszystkie biblioteki klas niezbędne do tworzenia aplikacji internetowych. Znajdują się one w katalogu <tomcat>\common\lib, gdzie <tomcat> to katalog instalacyjny serwera Tomcat:

Za pomocą przycisku „Add” dodamy te biblioteki, jedna po drugiej, do listy bibliotek przeszukiwanych przez JBuilder:

Od tej chwili można kompilować programy Java zgodne ze standardem J2EE, w szczególności serwlety Java. JBuilder służy wyłącznie do kompilacji, natomiast wykonanie jest później zapewniane przez Tomcat zgodnie z zasadami wyjaśnionymi w ramach kursu.
8.2. Kod źródłowy programów
8.2.1. Ogólny klient TCP
Wiele usług powstałych w początkach Internetu działa zgodnie z modelem serwera echo, który omówiliśmy wcześniej: komunikacja między klientem a serwerem odbywa się poprzez wymianę wierszy tekstu. Napiszemy ogólny klient TCP, który będzie uruchamiany w następujący sposób: java cltTCPgenerique serwer port
Ten klient TCP połączy się z portem port serwera serveur. Następnie utworzy dwa wątki:
- wątek odpowiedzialny za odczytywanie poleceń wpisywanych z klawiatury i wysyłanie ich do serwera
- wątek odpowiedzialny za odczytywanie odpowiedzi z serwera i wyświetlanie ich na ekranie
Dlaczego dwa wątki? Każda usługa TCP-IP ma swój własny protokół i czasami zdarzają się następujące sytuacje:
- klient musi wysłać kilka wierszy tekstu, zanim otrzyma odpowiedź
- odpowiedź serwera może zawierać kilka wierszy tekstu
Dlatego pętla polegająca na wysyłaniu pojedynczego wiersza do serwera – a następnie odbieraniu pojedynczego wiersza wysłanego przez serwer – nie zawsze jest odpowiednia. Stworzymy zatem dwie oddzielne pętle:
- pętlę odczytu poleceń wpisywanych z klawiatury w celu wysłania ich do serwera. Użytkownik zasygnalizuje koniec poleceń za pomocą słowa kluczowego fin.
- pętlę odbierania i wyświetlania odpowiedzi z serwera. Będzie to pętla nieskończona, która zostanie przerwana jedynie przez zamknięcie strumienia sieciowego przez serwer lub przez użytkownika za pomocą klawiatury, który wpisze polecenie fin.
Aby te dwie pętle były od siebie oddzielone, potrzebujemy dwóch niezależnych wątków. Przedstawmy przykład wykonania, w którym nasz ogólny klient TCP łączy się z usługą SMTP (SendMail Transfer Protocol). Usługa ta odpowiada za dostarczanie wiadomości e-mail do ich odbiorców. Działa ona na porcie 25 i wykorzystuje protokół komunikacyjny oparty na wymianie wierszy tekstowych.
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]
Omówmy tę wymianę danych między klientem a serwerem:
- usługa SMTP wysyła wiadomość powitalną, gdy klient nawiązuje z nią połączenie:
- niektóre usługi posiadają polecenie help, które zawiera informacje o poleceniach dostępnych w ramach tej usługi. W tym przypadku tak nie jest. Polecenia SMTP użyte w przykładzie są następujące:
- mail from: expéditeur, służące do podania adresu e-mail nadawcy wiadomości
- rcpt to: destinataire, w celu podania adresu e-mail odbiorcy wiadomości. Jeśli jest kilku odbiorców, polecenie rcpt to: należy powtórzyć tyle razy, ile jest to konieczne, dla każdego z nich.
- data, które sygnalizuje serwerowi SMTP, że zamierzamy wysłać wiadomość. Jak wskazano w odpowiedzi serwera, wiadomość ta jest ciągiem wierszy zakończonym wierszem zawierającym wyłącznie znak kropki. Wiadomość może zawierać nagłówki oddzielone od treści wiadomości pustym wierszem. W naszym przykładzie umieściliśmy temat za pomocą słowa kluczowego Subject:
- po wysłaniu wiadomości można poinformować serwer o zakończeniu operacji za pomocą polecenia quit. Serwer zamknie wówczas połączenie sieciowe. Wątek odczytu może wykryć to zdarzenie i zatrzymać się.
- Następnie użytkownik wpisuje na klawiaturze „fin”, aby zatrzymać również wątek odczytu poleceń wpisywanych z klawiatury.
Jeśli sprawdzimy otrzymaną wiadomość, zobaczymy następujący wpis (Outlook):

Należy zauważyć, że usługa SMTP nie jest w stanie wykryć, czy nadawca jest prawidłowy, czy nie. Dlatego nigdy nie można ufać polu from w wiadomości. W tym przypadku nadawca machin@univ-angers.fr nie istniał.
Ten ogólny klient TCP pozwala nam zidentyfikować protokół komunikacyjny usług internetowych, a na tej podstawie stworzyć wyspecjalizowane klasy dla klientów tych usług. Przyjrzyjmy się protokołowi komunikacyjnemu usługi POP (Post Office Protocol), który umożliwia odzyskiwanie wiadomości e-mail przechowywanych na serwerze. Działa on na porcie 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]
Główne polecenia są następujące:
- user login, gdzie podaje się swoją nazwę użytkownika na serwerze przechowującym nasze wiadomości e-mail
- pass password, gdzie podaje się hasło powiązane z poprzednią nazwą użytkownika
- list – wyświetla listę wiadomości w postaci numeru i rozmiaru w bajtach
- retr i – służy do odczytania wiadomości nr i
- quit – w celu zakończenia sesji.
Przyjrzyjmy się teraz protokołowi komunikacji między klientem a serwerem WWW, który zazwyczaj działa na porcie 80:
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]
Klient internetowy wysyła swoje polecenia do serwera zgodnie z poniższym schematem:
Serwer WWW odpowiada dopiero po otrzymaniu pustego wiersza. W tym przykładzie użyliśmy tylko jednego polecenia:
które żąda od serwera pliku URL /index.html i wskazuje, że korzysta z protokołu HTTP w wersji 1.0. Najnowsza wersja tego protokołu to 1.1. Przykład pokazuje, że serwer odpowiedział, wysyłając zawartość pliku index.html, a następnie zamknął połączenie, co widać po zakończeniu działania wątku odczytu odpowiedzi. Przed wysłaniem zawartości pliku index.html serwer WWW wysłał serię nagłówków zakończoną pustym wierszem:
<-- 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>
Wiersz <html> jest pierwszym wierszem pliku /index.html. Powyższe elementy nazywane są nagłówkami HTTP (HyperText Transfer Protocol). Nie będziemy tutaj szczegółowo omawiać tych nagłówków, ale warto pamiętać, że nasz klient generyczny zapewnia do nich dostęp, co może być pomocne w ich zrozumieniu. Na przykład pierwszy wiersz:
wskazuje, że serwer WWW, z którym nawiązano połączenie, obsługuje protokół HTTP/1.1 i że pomyślnie znalazł żądany plik (200 OK), przy czym 200 jest kodem odpowiedzi HTTP. Wiersze
informują klienta, że otrzyma 11251 bajtów reprezentujących tekst HTML (HyperText Markup Language) oraz że po zakończeniu wysyłania połączenie zostanie zamknięte.
Mamy więc do czynienia z bardzo praktycznym klientem TCP. Z pewnością oferuje on mniej funkcji niż oficjalny program telnet, ale warto było napisać go samodzielnie. Kod programu generycznego klienta TCP wygląda następująco:
// zaimportowane pakiety
import java.io.*;
import java.net.*;
public class clientTCPgenerique{
// przyjmuje jako parametr charakterystykę usługi w postaci
// port serwera
// łączy się z usługą
// tworzy wątek do odczytu poleceń wpisywanych z klawiatury
// polecenia te zostaną wysłane do serwera
// tworzy wątek do odczytu odpowiedzi z serwera
// odpowiedzi te zostaną wyświetlone na ekranie
// całość kończy się poleceniem „fin” wpisanym na klawiaturze
// zmienna instancji
private static Socket client;
public static void main(String[] args){
// składnia
final String syntaxe="pg serveur port";
// liczba argumentów
if(args.length != 2)
erreur(syntaxe,1);
// należy podać nazwę serwera
String serveur=args[0];
// port musi być liczbą całkowitą większą od 0
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;
// mogą wystąpić problemy
try{
// nawiązuje się połączenie z usługą
client=new Socket(serveur,port);
}catch(Exception ex){
// błąd
erreur("Impossible de se connecter au service ("+ serveur
+","+port+"), erreur : "+ex.getMessage(),3);
// koniec
return;
}//catch
// tworzymy wątki odczytu/zapisu
new ClientSend(client).start();
new ClientReceive(client).start();
// koniec wątku głównego
return;
}// main
// wyświetlanie błędów
public static void erreur(String msg, int exitCode){
// wyświetlanie błędu
System.err.println(msg);
// zakończenie z błędem
System.exit(exitCode);
}//błąd
}//klasa
class ClientSend extends Thread {
// klasa odpowiedzialna za odczytywanie poleceń wpisywanych z klawiatury
// oraz wysyłania ich na serwer za pośrednictwem klienta TCP przekazanego jako parametr
private Socket client; // klient TCP
// konstruktor
public ClientSend(Socket client){
// odnotowujemy klienta TCP
this.client=client;
}//konstruktor
// metoda Run wątku
public void run(){
// dane lokalne
PrintWriter OUT=null; // strumień zapisu sieciowego
BufferedReader IN=null; // strumień klawiatury
String commande=null; // polecenie odczytane z klawiatury
// obsługa błędów
try{
// tworzenie strumienia zapisu sieciowego
OUT=new PrintWriter(client.getOutputStream(),true);
// tworzenie strumienia danych z klawiatury
IN=new BufferedReader(new InputStreamReader(System.in));
// pętla wprowadzania i wysyłania poleceń
System.out.println("Commandes : ");
while(true){
// odczyt polecenia wprowadzonego z klawiatury
commande=IN.readLine().trim();
// koniec?
if (commande.toLowerCase().equals("fin")) break;
// wysyłanie polecenia do serwera
OUT.println(commande);
// następne polecenie
}//while
}catch(Exception ex){
// błąd
System.err.println("Envoi : L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// koniec – zamykanie strumieni
try{
OUT.close();client.close();
}catch(Exception ex){}
// zgłaszamy zakończenie wątku
System.out.println("[Envoi : fin du thread d'envoi des commandes au serveur]");
}//run
}//klasa
class ClientReceive extends Thread{
// klasa odpowiedzialna za odczytywanie wierszy tekstu przeznaczonych dla
// klienta TCP przekazanego jako parametr
private Socket client; // klient TCP
// konstruktor
public ClientReceive(Socket client){
// odnotowujemy klienta TCP
this.client=client;
}//konstruktor
// metoda Run wątku
public void run(){
// dane lokalne
BufferedReader IN=null; // strumień odczytu sieciowego
String réponse=null; // odpowiedź serwera
// obsługa błędów
try{
// tworzenie strumienia odczytu sieciowego
IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
// pętla odczytu wierszy tekstowych ze strumienia IN
while(true){
// odczyt strumienia sieciowego
réponse=IN.readLine();
// strumień zamknięty?
if(réponse==null) break;
// wyświetlanie
System.out.println("<-- "+réponse);
}//while
}catch(Exception ex){
// błąd
System.err.println("Réception : L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// koniec – strumienie są zamykane
try{
IN.close();client.close();
}catch(Exception ex){}
// zgłaszamy zakończenie wątku
System.out.println("[Réception : fin du thread de lecture des réponses du serveur]");
}//uruchom
}//klasa
8.2.2. Ogólny serwer TCP
Teraz zajmiemy się serwerem,
- , który wyświetla na ekranie polecenia wysyłane przez klientów
- i wysyła im w odpowiedzi wiersze tekstu wpisane przez użytkownika na klawiaturze. To właśnie użytkownik pełni rolę serwera.
Program uruchamia się poleceniem: java serveurTCPgenerique portEcoute, gdzie portEcoute to port, z którym klienci muszą się połączyć. Obsługa klienta będzie zapewniana przez dwa wątki:
- wątek zajmujący się wyłącznie odczytywaniem wierszy tekstu wysyłanych przez klienta
- wątek zajmujący się wyłącznie odczytywaniem odpowiedzi wpisywanych przez użytkownika na klawiaturze. Serwer zasygnalizuje za pomocą polecenia „fin”, że zamyka połączenie z klientem.
Serwer tworzy dwa wątki na każdego klienta. Jeśli jest n klientów, jednocześnie będzie aktywnych 2n wątków. Sam serwer nigdy się nie zatrzymuje, chyba że użytkownik naciśnie na klawiaturze klawisze Ctrl-C. Przyjrzyjmy się kilku przykładom.
Serwer uruchomiono na porcie 100 i do komunikacji z nim używamy klienta ogólnego. Okno klienta wygląda następująco:
E:\data\serge\MSNET\c#\sieć\klient tcp ogólny> 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]
Wiersze zaczynające się od <-- to te wysyłane z serwera do klienta, pozostałe to te wysyłane z klienta do serwera. Okno serwera wygląda następująco:
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]
Wiersze zaczynające się od <-- to te wysłane przez klienta do serwera. Wiersze oznaczone numerem N to te wysłane przez serwer do klienta nr N. Powyższy serwer nadal działa, podczas gdy klient 1 zakończył działanie. Uruchamiamy drugiego klienta dla tego samego serwera:
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]
Okno serwera wygląda wówczas następująco:
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
Teraz zasymulujmy serwer WWW, uruchamiając nasz serwer ogólnego przeznaczenia na porcie 88:
Dos> java serveurTCPgenerique 88
Serveur générique lancé sur le port 88
Otwórzmy teraz przeglądarkę i wpiszmy adres http://localhost:88/exemple.html. Przeglądarka połączy się wówczas z portem 88 na serwerze localhost, a następnie zażąda strony /exemple.html:

Przyjrzyjmy się teraz oknu naszego serwera:
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
<--
W ten sposób odkrywamy nagłówki HTTP wysyłane przez przeglądarkę. Pozwala nam to stopniowo poznawać protokół HTTP. W poprzednim przykładzie stworzyliśmy klienta internetowego, który wysyłał tylko jedno polecenie GET. To wystarczyło. Widzimy tutaj, że przeglądarka wysyła do serwera dodatkowe informacje. Ich celem jest wskazanie serwerowi, z jakim typem klienta ma do czynienia. Widzimy również, że nagłówki HTTP kończą się pustym wierszem.
Przygotujmy odpowiedź dla naszego klienta. Użytkownik korzystający z klawiatury jest tutaj prawdziwym serwerem i może ręcznie przygotować odpowiedź. Przypomnijmy sobie odpowiedź wysłaną przez serwer WWW w poprzednim przykładzie:
<-- 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>
Spróbujmy udzielić podobnej odpowiedzi:
...
<-- 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]
Wiersze zaczynające się od 2: są wysyłane z serwera do klienta nr 2. Polecenie fin zamyka połączenie serwera z klientem. W naszej odpowiedzi ograniczyliśmy się do następujących nagłówków HTTP:
HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :
Nie podajemy rozmiaru pliku, który zamierzamy wysłać (Content-Length), a jedynie informujemy, że po jego wysłaniu zamkniemy połączenie (Connection: close). To wystarczy dla przeglądarki. Gdy przeglądarka zauważy, że połączenie zostało zamknięte, uzna, że odpowiedź serwera została zakończona i wyświetli stronę HTML, która została jej przesłana. Wygląda ona następująco:
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>
Następnie użytkownik zamyka połączenie z klientem, wpisując polecenie fin. Przeglądarka rozpoznaje wówczas, że odpowiedź serwera została zakończona i może ją wyświetlić:

Jeśli w powyższym przykładzie wpiszemy polecenie View/Source, aby sprawdzić, co otrzymała przeglądarka, otrzymamy:

czyli dokładnie to, co wysłano z serwera generycznego.
Kod serwera TCP o charakterze ogólnym wygląda następująco:
// pakiety
import java.io.*;
import java.net.*;
public class serveurTCPgenerique{
// program główny
public static void main (String[] args){
// odbiera żądania klientów na porcie nasłuchowym
// tworzy wątek do odczytu żądań klienta
// zostaną one wyświetlone na ekranie
// tworzy wątek do odczytu poleceń wpisywanych z klawiatury
// polecenia te zostaną wysłane jako odpowiedź do klienta
// całość kończy się poleceniem „fin” wprowadzonym z klawiatury
final String syntaxe="Syntaxe : pg port";
// zmienna instancji
// czy istnieje argument
if(args.length != 1)
erreur(syntaxe,1);
// port musi być liczbą całkowitą większą od 0
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);
// tworzymy serwis nasłuchujący
ServerSocket ecoute=null;
int nbClients=0; // liczba obsłużonych klientów
try{
// tworzymy usługę
ecoute=new ServerSocket(port);
// monitorowanie
System.out.println("Serveur générique lancé sur le port " + port);
// pętla obsługi klientów
Socket client=null;
while (true){ // pętla nieskończona – zostanie zatrzymana przez Ctrl-C
// oczekiwanie na klienta
client=ecoute.accept();
// usługa jest realizowana przez oddzielne wątki
nbClients++;
// tworzenie wątków odczytu/zapisu
new ServeurSend(client,nbClients).start();
new ServeurReceive(client,nbClients).start();
// powrót do nasłuchiwania żądań
}// koniec pętli while
}catch(Exception ex){
// zgłaszamy błąd
erreur("L'erreur suivante s'est produite : " + ex.getMessage(),3);
}//catch
}// koniec funkcji main
// wyświetlanie błędów
public static void erreur(String msg, int exitCode){
// wyświetlanie błędu
System.err.println(msg);
// zatrzymanie z błędem
System.exit(exitCode);
}//błąd
}//klasa
class ServeurSend extends Thread{
// klasa odpowiedzialna za odczytywanie odpowiedzi wpisywanych z klawiatury
// i wysyłania ich do klienta za pośrednictwem klienta TCP przekazanego do konstruktora
Socket client; // klient TCP
int numClient; // numer klienta
// konstruktor
public ServeurSend(Socket client, int numClient){
// odnotowujemy klienta TCP
this.client=client;
// oraz jego numer
this.numClient=numClient;
}//producent
// metoda Run wątku
public void run(){
// dane lokalne
PrintWriter OUT=null; // strumień zapisu sieciowego
String réponse=null; // odpowiedź odczytana z klawiatury
BufferedReader IN=null; // strumień klawiatury
// monitorowanie
System.out.println("Thread de lecture des réponses du serveur au client "+ numClient + " lancé");
// obsługa błędów
try{
// tworzenie strumienia zapisu sieciowego
OUT=new PrintWriter(client.getOutputStream(),true);
// tworzenie strumienia klawiatury
IN=new BufferedReader(new InputStreamReader(System.in));
// pętla wprowadzania i wysyłania poleceń
while(true){
// identyfikacja klienta
System.out.print("--> " + numClient + " : ");
// odczyt odpowiedzi wpisanej z klawiatury
réponse=IN.readLine().trim();
// koniec?
if (réponse.toLowerCase().equals("fin")) break;
// wysłanie odpowiedzi na serwer
OUT.println(réponse);
// następna odpowiedź
}//while
}catch(Exception ex){
// błąd
System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// koniec – zamykanie strumieni
try{
OUT.close();client.close();
}catch(Exception ex){}
// zgłaszamy zakończenie wątku
System.out.println("[fin du Thread de lecture des réponses du serveur au client "+ numClient+ "]");
}//run
}//klasa
class ServeurReceive extends Thread{
// klasa odpowiedzialna za odczytywanie wierszy tekstu wysyłanych do serwera
// za pośrednictwem klienta TCP przekazanego do konstruktora
Socket client; // klient TCP
int numClient; // numer klienta
// konstruktor
public ServeurReceive(Socket client, int numClient){
// odnotowujemy klienta TCP
this.client=client;
// oraz jego numer
this.numClient=numClient;
}//producent
// metoda Run wątku
public void run(){
// dane lokalne
BufferedReader IN=null; // strumień odczytu sieciowego
String réponse=null; // odpowiedź serwera
// śledzenie
System.out.println("Thread de lecture des demandes du client "+ numClient + " lancé");
// obsługa błędów
try{
// tworzenie strumienia odczytu sieciowego
IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
// pętla odczytu wierszy tekstowych ze strumienia IN
while(true){
// odczyt strumienia sieciowego
réponse=IN.readLine();
// strumień zamknięty?
if(réponse==null) break;
// wyświetlanie
System.out.println("<-- "+réponse);
}//while
}catch(Exception ex){
// błąd
System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// koniec – zamykamy strumienie
try{
IN.close();client.close();
}catch(Exception ex){}
// zgłaszamy zakończenie wątku
System.out.println("[fin du Thread de lecture des demandes du client "+ numClient+"]");
}//run
}//klasa
8.3. JAVASCRIPT
W tej części przedstawiamy trzy przykłady wykorzystania JavaScriptu na stronach WEB. Skupiamy się na obsłudze formularzy, ale JavaScript ma znacznie szersze możliwości.
8.3.1. Pobieranie informacji z formularza
Poniższy przykład pokazuje, jak pobrać w przeglądarce dane wprowadzone przez użytkownika w formularzu. Zazwyczaj pozwala to na wstępne przetworzenie danych przed wysłaniem ich na serwer.
8.3.1.1. Formularz
Mamy formularz zawierający najczęściej spotykane elementy oraz przycisk „Wyświetl”, który pozwala wyświetlić dane wprowadzone przez użytkownika.

8.3.1.2. Kod
<html>
<head>
<title>Un formulaire traité par Javascript</title>
<script language="javascript">
function afficher(){
// wyświetla informacje z formularza na liście
// najpierw się kasuje
effacerInfos();
// wyświetla wartości # pól
with(document.frmExemple){
// pole ukryte
ecrire("champ caché="+cache.value);
// pole tekstowe pojedyncze
ecrire("champ textuel simple="+simple.value);
// pole tekstowe z wieloma wartościami
ecrire("champ textuel multiple="+lignes.value);
// przyciski opcji
for(i=0;i<radio.length;i++){
texte="radio["+i+"]="+radio[i].value;
if(radio[i].checked) texte+=", coché";
ecrire(texte);
}//for
// pola wyboru
for(i=0;i<qcm.length;i++){
texte="qcm["+i+"]="+qcm[i].value;
if(qcm[i].checked) texte+=", coché";
ecrire(texte);
}//for
//lista rozwijana
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);
}//dla
//lista wielokrotnego wyboru
for(i=0;i<lstVoitures.length;i++){
texte="lstVoitures["+i+"]="+lstVoitures.options[i].text;
if(lstVoitures.options[i].selected) texte+=",sélectionné";
ecrire(texte);
}//dla
//hasło
ecrire("mot de passe="+passwd.value);
}//z
}//funkcja
function ecrire(texte){
// zapisuje tekst na liście informacji
frmInfos.lstInfos.options[frmInfos.lstInfos.length]=new Option(texte);
}//zapisać
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"> </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"> </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> </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> </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. Wyrażenia regularne w JavaScript
W przeglądarce JavaScript może służyć do sprawdzania poprawności danych wprowadzonych przez użytkownika przed wysłaniem ich na serwer. Oto program do testowania tych wyrażeń regularnych.
8.3.2.1. Strona testowa

8.3.2.2. Kod strony
<html>
<head>
<title>Les expressions régulières en Javascript</title>
<script language="javascript">
function afficherInfos(){
with(document.frmRegExp){
// coś do zrobienia?
if (! verifier()) return;
// w porządku – usuwamy poprzednie wyniki
effacerInfos();
// weryfikacja szablonu
modele=new RegExp(txtModele.value);
champs=modele.exec(txtChaine.value);
if(champs==null)
// brak zgodności między wzorem a ciągiem znaków
ecrireInfos("pas de correspondance");
else{
// zgodność – wyświetlamy uzyskane wyniki
ecrireInfos("Il y a correspondance");
for(i=0;i<champs.length;i++)
ecrireInfos("champs["+i+"]=["+champs[i]+"]");
}//w przeciwnym razie
}//with
}//funkcja
function ecrireInfos(texte){
// zapisuje tekst na liście informacji
document.frmRegExp.lstInfos.options[document.frmRegExp.lstInfos.length]=new Option(texte);
}//zapis
function effacerInfos(){
frmRegExp.lstInfos.length=0;
}//effacerInfos
function jouer(){
// sprawdza szablon względem ciągu znaków z wybranego przykładu
with(document.frmRegExp){
txtModele.value=lstModeles.options[lstModeles.selectedIndex].text
txtChaine.value=lstChaines.options[lstChaines.selectedIndex].text
afficherInfos();
}//z
}//odtworzyć
function ajouter(){
//dodaje bieżący test do przykładów
with(document.frmRegExp){
// coś do zrobienia?
if (! verifier()) return;
// dodaj
lstModeles.options[lstModeles.length]=new Option(txtModele.value);
lstChaines.options[lstChaines.length]=new Option(txtChaine.value);
// wyczyść wprowadzone dane
txtModele.value="";
txtChaine.value="";
}//z
}//dodaj
function verifier(){
// sprawdź, czy pola wprowadzania danych nie są puste
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;
}//jeśli
// w porządku
return true;
}//z
}//sprawdź
</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. Zarządzanie listami w JavaScript
8.3.3.1. Formularz

8.3.3.2. Kod
<html>
<head>
<title>Les listes en Javascript</title>
<script language="javascript">
// dodaj
function ajouter(L1,L2,T){
// dodaj wartość pola T do list L1, L2
// coś do zrobienia?
champs=/^\s*$/.exec(T.value);
if(champs!=null){
// pole jest puste
alert("Vous n'avez pas indiqué la valeur à ajouter");
txtElement.focus();
return;
}//if
// dodajemy element
L1.options[L1.length]=new Option(T.value);
L2.options[L2.length]=new Option(T.value);
T.value="";
}//dodaj
//wyczyść
function vider(L){
// opróżnia listę L
L.length=0;
}//opróżnij
//przeniesienie
function transfert(L1,L2,simple){
//przenosi do L2 elementy zaznaczone na liście L1
// coś do zrobienia?
// indeks wybranego elementu z listy L1
index1=L1.selectedIndex;
if(index1==-1){
alert("Vous n'avez pas sélectionné d'élément");
return;
}//if
// jaki jest tryb wyboru elementów z list
if(simple){ // wybór pojedynczy
element1=L1.options[index1].text;
//dodawanie w L2
L2.options[L2.length]=new Option(element1);
//usuwanie w L1
L1.options[index1]=null;
}//pojedynczy
if(! simple){ //wybór wielokrotny
//przeglądanie listy 1 w odwrotnym kierunku
for(i=L1.length-1;i>=0;i--){
//czy element jest zaznaczony?
if(L1.options[i].selected){
//dodaj do L2
L2.options[L2.length]=new Option(L1.options[i].text);
//usuwa się go z L1
L1.options[i]=null;
}//if
}//dla i
}//if ! proste
}//przelew
</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>


