Skip to content

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

  1. Główne serwery WWW
    • Apache (Linux, Windows)
    • Interner Information Server IIS (NT), Personal Web Server PWS (Windows 9x)
  1. Główne przeglądarki
    • Internet Explorer (Windows)
    • Netscape (Linux, Windows)
  1. 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
  1. Języki skryptowe po stronie przeglądarki
    • VBScript (IE)
    • JavaScript (IE, Netscape)
    • PerlScript (IE)
    • Java (IE, Netscape)

8.1.2. Gdzie znaleźć narzędzia

Netscape
http://www.netscape.com/ (link do plików do pobrania)
Internet Explorer
http://www.microsoft.com/windows/ie/default.asp
PHP
http://www.php.net
http://www.php.net/downloads.php (pliki binarne dla systemu Windows)
PERL
http://www.activestate.com http://www.activestate.com/Products/
http://www.activestate.com/Products/ActivePerl/
Vbscript, Javascript
http://msdn.microsoft.com/scripting (kliknij link „skrypt Windows”)
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
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
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

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:

Image

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

Image

easyphp.exe
plik wykonywalny aplikacji
apache
struktura katalogów serwera Apache
mysql
struktura katalogów bazy danych MySQL SGBD
phpmyadmin
struktura katalogów aplikacji phpMyAdmin
php
struktura katalogów php
www
katalog główny drzewa stron internetowych dostarczanych przez serwer Apache EasyPHP
cgi-bin
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:

Image

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

Image

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:

Image

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

Image

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.

Image

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.

Image

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

Image

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:

Image

Aby zakończyć nasz przykład, możemy teraz umieścić strony internetowe w drzewie katalogów e:\data\serge\web:

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

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

i wywołać tę stronę, używając aliasu st:

Image

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:

Port 81

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:

Image

Oto kilka ważnych informacji dotyczących tego pliku konfiguracyjnego:

ligne(s)
rola
ServerRoot "D:/Program Files/Apache Group/Apache"
wskazuje folder, w którym znajduje się drzewo katalogów Apache
Port 80
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
ServerAdmin root@istia.univ-angers.fr
adres e-mail administratora serwera Apache
ServerName stahe.istia.uang
nazwa komputera, na którym „działa” serwer Apache
ServerRoot "E:/Program Files/EasyPHP/apache"
katalog instalacyjny serwera Apache. Gdy w pliku konfiguracyjnym pojawiają się nazwy plików względne, odnoszą się one do tego katalogu.
DocumentRoot "E:/Program Files/EasyPHP/www"
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
<Directory "E:/Program Files/EasyPHP/www">
ustala właściwości poprzedniego folderu
ErrorLog logs/error.log
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.
    ScriptAlias /cgi-bin/ "E:/Program Files/EasyPHP/cgi-bin/"
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.
<Directory "E:/Program Files/EasyPHP/cgi-bin/">
ustala właściwości powyższego folderu
LoadModule php4_module "E:/Program
 Files/EasyPHP/php/php4apache.dll"
AddModule mod_php4.c
wiersze ładujące moduły umożliwiające Apache'owi współpracę z PHP4.
    AddType application/x-httpd-php
 .phtml .pwml .php3 
.php4 .php .php2 .inc
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:

Image

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:

Image

Jeśli klikniemy link Afficher z user:

Image

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:

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

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:

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

  1. Uruchom program:
D:\data\java\essais>c:\jdk1.3\bin\java heure
Il est 10:44:2

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
conf
katalog plików konfiguracyjnych serwera Apache
logs
katalog plików logów (monitorowania) serwera Apache
bin
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.

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:

Image

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

Image

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:

  1. 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
;
  1. 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ć.
  2. Uruchom serwer Apache, jeśli jeszcze tego nie zrobiono
  3. W przeglądarce należy wywołać plik URL pod adresem http://localhost/cgi-bin/heure.pl. Wyświetli się następująca strona:

Image

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:

Image

  1. 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"
  1. Uruchom ponownie komputer, aby zmiany w rejestrze zostały uwzględnione.
  1. 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:
Répertoire/Parcourir : d:\inetpub\wwwroot\php
Alias : php
Cocher la case exécuter.
  1. Potwierdź zmiany i uruchom ponownie PWS. Umieść w d:\inetpub\wwwroot\php plik intro.php zawierający wyłącznie następujący wiersz:
<? phpinfo() ?>
  1. 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>:

Image

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:

Start Tomcat
aby uruchomić Tomcat
Stop Tomcat
do jego wyłączenia

Po uruchomieniu Tomcata pojawia się okno DOS z następującą treścią:

Image

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:

Image

Kliknij link „Servlet Examples”:

Image

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

Image

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

Image

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:

Image

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

Image

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:

  1. wątek odpowiedzialny za odczytywanie poleceń wpisywanych z klawiatury i wysyłanie ich do serwera
  2. 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:
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
  • 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):

Image

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:

commande1
commande2
...
commanden
[ligne vide]

Serwer WWW odpowiada dopiero po otrzymaniu pustego wiersza. W tym przykładzie użyliśmy tylko jednego polecenia:

GET /index.html HTTP/1.0

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:

<-- HTTP/1.1 200 OK

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

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

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:

Image

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

Image

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

Image

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.

Image

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">&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. 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

Image

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

Image

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>