WWW

Perl FAQ | RecentChanges | Preferences

1. Jak pisać CGI?
2. Czym się różni Perl od CGI?
3. Jak przetwarzać formularz (z modułem CGI)?
4. Co to jest cgi-lib?
5. Jak wysyłać odpowiedź do przeglądarki?
6. Jak wysłać plik do przeglądarki?
7. Jak wysłać plik z dysku na serwer WWW?
8. Jak ściągnąć plik z określonego odniesienia URL?
9. Jak wysłać wypełniony formularz (metoda POST)?
10. Czego użyć do zaawansowanych ściągań?
11. Czy są biblioteki do FTP?
12. Czy można przekierować przeglądarkę na inny URL?
13. A co z ciastkami (cookies)?
14. Jak identyfikować oglądacza WWW?
15. Czy jest wbudowany mechanizm sesji?
16. Jak wysłać po sobie kilka stron?
17. Co to są wstawki SSI i jak ich używać?
18. Jak uruchamiać CGI pod DOS/Windows?
19. Jak automatycznie wypełnić formularz?
20. Jak pisać licznik?
21. Jak pisać książkę gości?
22. Jak wykonać zadania systemowe przez WWW?
23. Co to jest mod_perl?
24. Jak zacząć z FastCGI?
25. Jak połączyć Perla z HTML-em?

1. Jak pisać CGI?

CGI, czyli Common Gateway Interface, to zestaw reguł, które musi spełnić program (napisany w dowolnym języku, w tym w Perlu), aby można go było "podpiąć" do serwera WWW tak, aby serwer go uruchamiał, a do przeglądarki wysyłał wynik działania tego programu.

Zadaniem skryptu CGI jest odebranie parametrów żądania z metody GET lub POST (na przykład wypełnionego formularza), wykonanie związanych z tym zadań i wygenerowanie odpowiedzi zawierającej stronę (lub fragment) HTML.

Specyfikacja protokołu do komunikacji z serwerem WWW (HTTP 1.1) znajduje się w dokumencie RFC 2616 dostępnym w archiwach rfc.

2. Czym się różni Perl od CGI?

CGI nie jest językiem programowania, jak Perl. Jest pewnym standardem wymiany informacji pomiędzy serwerem, a przeglądarką. Można go realizować w każdym języku, który potrafi wysyłac tekst na STDOUT. Perl jest bardzo wygodny ze względu na duże możliwości przy przetwarzaniu tekstów.

W perlu pomocny jest moduł CGI. Przed umieszczeniem skryptu na serwerze dobrze jest go przetestować (patrz testowanie skryptów).

3. Jak przetwarzać formularz (z modułem CGI)?

Służy do tego moduł CGI

 use CGI;                        # zaladowanie modulu
 $cgi = new CGI;                 # nowy obiekt typu CGI
 $pliczek = $cgi->param("log");  # pod zmienna pliczek podstaw wartość pola log

 #zapisanie całego formularza do pliku o nazwie wartosci
 open (OUT,">wartosci");	 # otwarcie pliku
 $cgi->save(OUT);		 # zapis
 close OUT;			 # zamkniecie

W zmiennej $pliczek znajdzie się napis z polskimi literami (o ile wystąpiły) i innymi znakami, które będą już zdekodowane. Najprawdopodobniej polskie litery będą w standardzie CP i to trzeba poprawić (patrz poprawianie polskich liter).

Oprócz odebrania danych należy wysłać odpowiedź do przeglądarki.

4. Co to jest cgi-lib?

Biblioteka cgi-lib jest hitoryczną zaszłością i zamiast niej używa się standardowego modułu CGI. Jeśli zachodzi potrzeba wykorzystania kodu używającego tej biblioteki poleca się następującą zamianę:

 require 'cgi-lib.pl';
 &ReadParse;
 $wartosc_query_w_url = $in{'query'};

na

 use CGI;
 CGI::ReadParse();
 $wartosc_query_w_url = $in{'query'};

5. Jak wysyłać odpowiedź do przeglądarki?

Dobrze jest użyć do tego modułu CGI, lub zawsze pamiętać o linijce zawierającej Content-type: np.

 print "Content-type: text/html\n\n";

linia ta jest obowiązkowa i wraz innymi dodatkowymi tworzy nagłówki. Po wszystkich liniach nagłówków musi być pusta linia. Brak tych dwóch kryteriów daje błąd "500 Internal Server Error".

Każdy skrypt CGI, zanim wypisze na STDOUT zawartość strony, musi wypisać kilka magicznych linijek tworzących tzw. nagłówek - pozwala on np. serwerowi stwierdzić co konkretnie przesyłamy (HTML, tekst, obrazek). Zasadniczo to o czym większość początkujących musi wiedzieć, to że na początku skryptu w perlu trzeba umieścić coś takiego:

 print "Content-type: text/html; charset=ISO-8859-2\n\n";

lub

 use CGI qw(:standard);
 $query = new CGI;
 print $query->header(-type => 'text/html', -charset => 'ISO-8859-2');

Spowoduje to wyświetlenie nagłówka zawierającego jedną linię, która z kolei informuje co będziemy przesyłać (dokument HTML) oraz przy okazji podaje sposób kodowania polskich liter jako ISO-8859-2 (jeżeli w danym dokumencie nie ma polskich znaczków, można pominąć średnik i "charset=...")

Zamiast "text/html" możemy umieszczać także np. "text/plain" jeżeli przesyłamy dokument tekstowy (nie HTML), albo "image/gif" lub "image/jpeg" jeżeli przesyłamy obrazek odpowiedni GIF lub JPG (wtedy po nagłówku wypisujemy zawartość pliku z obrazkiem "jak leci" bajt po bajcie).

Po wypisaniu w ten sposób nagłówka możemy już wypisywać cokolwiek (chociaż dobrze byłoby żeby było to poprawny HTML - chyba że w nagłówku podaliśmy inny typ danych).

Dla obsługi WAP konieczny jest zamiennik:

 print "Content-type: text/vnd.wap.wml\n\n";

Niestety to nie wystarczy. Musisz jeszcze dodać linijki:

 <?xml version="1.0"?>
 <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN"
  "http://www.wapforum.org/DTD/wml12.dtd>;

No w końcu reszta nie może być pisana w HTML, ale w WML. Język to podobny do HTML, ale ma kilka haczyków:))

6. Jak wysłać plik do przeglądarki?

 print "Content-type: application/octet-stream\n";
 print "Content-Disposition: attachment;
   filename=NAZWA_PLIKU_Z_ROZSZERZENIEM\n\n";

Otwieramy plik binarnie i wypluwamy do przeglądarki:

 open AA,"plik.bin";
 #binmode STDOUT;        #w niektorych systemach ta jest linia potrzebna
 #binmode AA;		 #jak wyzej
 print join '',<AA>;     #te linie mozna zamienic na: undef $/; print <AA>;
 close AA;

W IE może wystąpić problem zapisu jako index.html, trzeba wówczas w <a href= wywołojącym skrypt dodać target=_blank.

7. Jak wysłać plik z dysku na serwer WWW?

Można to wykonać jedynie przez metodę POST. Trzeba napisać w kodzie HTMLa formularz z liniami:

 <form method="post" enctype="multipart/form-data" action="skrypt.cgi">
 <input type="file" name="uploaded_file">

a w Perlu:

 use CGI;
 $query = new CGI;
 $fh = $query->upload('uploaded_file');    # nazwa pliku
 #$fh = $query->param('uploaded_file');    # dla starszych wersji
 #typ zawartosci pliku:
 $type = $query->uploadInfo($fh)->{'Content-Type'};
 #naglowek:
 print $query->header(-type=>$type);

 #wypisanie pliku na ekran:
 while (<$fh>) { print; }

Niekiedy może być potrzebne użycie konstrukcji

 use CGI qw(-private_tempfiles);

a także ustawienie binmode OUTFILE. Dane charakterystyczne można dostać:

 %hash=%{$dane->uploadInfo($file)};
 foreach (keys(%hash)) {print "$_ -> $hash{$_}\n"};

Przed zbyt dużymi uploadami dobrze jest się zabezpieczyć przez:

 $CGI::POST_MAX=$ile_bajtow;

8. Jak ściągnąć plik z określonego odniesienia URL?

Za pomoca modułu LWP (perldoc lwpcook):

 use LWP::Simple;
 if ($tekst_strony = get('http://serwer/sciezka/plik')) 
 { print "udało się ściągnąć plik"; }
 else  { print "nie udało się ściągnąć pliku"; }

lub bardziej rozbudowana metoda:

 use LWP::UserAgent;
 $ua = new LWP::UserAgent;
 #ustawienie czego
 my $req = new HTTP::Request(GET => 'http://serwer/sciezka/plik');
 $ua->credentials("serwer:80","Areajakastam","user","haslo");  #jesli na haslo
 #sciagniecie
 my $res = $ua->request($req);
 #wypisanie
 if ($res->is_success) { print $res->content; }
 else {print $res->error_as_HTML; }

9. Jak wysłać wypełniony formularz (metoda POST)?

  use HTTP::Request::Common qw(POST);
  use LWP::UserAgent;
  $ua = LWP::UserAgent->new; 
  my $req = POST 'http://www.perl.com/cgi-bin/BugGlimpse',
     [ search => 'www', errors => 0 ];
  print $ua->request($req)->as_string; 

lub

 use LWP::UserAgent;
 my $ua = LWP::UserAgent->new();
 $ua->agent('Mozilla/5.0');
 my %form = (
   'login' => 'user',
   'pass' => 'haslo',
 );
 my $response = $ua->post('http://url.do.strony/', \%form);

10. Czego użyć do zaawansowanych ściągań?

Poleca się moduł LWP::RobotUA, WWW::Robot lub WWW::Mechanize:

 my $www = new WWW::Mechanize;
 $www->get('http://search.cpan.org');
 $www->follow_link( text_regex => qr/jakies wyrazenie regularne/i );

Można także wykorzystać moduł IO::Socket, należy przy tym znać protokół HTTP.

 use IO::Socket;
 $misie=IO::Socket::INET->new(PeerAddr => "server.com", PeerPort => 80,
                          Timeout => 1, Proto => 'tcp');
 $misie->print("GET /sciezka/plik HTTP/1.0\n\n");
 while(<$misie>) { print; }

Alternatywą może też być Net::HTTP.

Dla obsługi https (HTTP+SSL) trzeba zainstalować OpenSSL, a następnie moduł Net::SSLeay lub Crypt::SSLeay.

11. Czy są biblioteki do FTP?

Do protokołu ftp używa się modułu Net::FTP, włączonego wraz z obsługą innych protokołów do biblioteki netlib.

  $ftp = Net::FTP->new("some.host.name", Debug => 0);
  $ftp->login("anonymous",'me@here.there');
  $ftp->cwd("/pub");
  $ftp->get("that.file");
  $ftp->quit;

12. Czy można przekierować przeglądarkę na inny URL?

Jest to możliwe jedynie przy użyciu metody GET. W tym celu nie należy wysyłać nagłówka z linią Content-type, a trzeba z linią Location. Moduł CGI ma funkcję redirect.

13. A co z ciastkami (cookies)?

Odbieranie:

 use CGI::Cookie; 
 my $zmienna;
 my %cookies = fetch CGI::Cookie;                 # hash z ciastkami
 if ( defined($cookies{'nazwa_ciacha'}) )    # jesli jest o tej nazwie
  { $zmienna = $cookies{'nazwa_ciacha'}->value; }  # sprawdz wartosc

 $cookie = $ENV{'HTTP_COOKIE'}; #zwraca wszystkie ciacha dla domeny

lub po prostu

 use CGI;
 $q = new CGI;
 $zmienna = $q->cookie('nazwa_ciacha');
 %answers = $q->cookie('answers');

Wysyłanie:

 use CGI qw/:standard/;
 use CGI::Cookie;

 $ciastko1 = new CGI::Cookie(-name => 'Liczba',-value =>  '2');
 $ciastko2 = new CGI::Cookie(-name => 'Name',-value => 'Michal');

 print header(-cookie=>[$ciastko1,$ciastko2]);
 # Uwaga: trzeba to wyslac przed wlasciwa trescia strony!!!

Inny moduł to HTTP::Cookies:

 use HTTP::Cookies;
 use LWP::UserAgent;

 my $ua = LWP::UserAgent->new;
 my $cookie_jar = HTTP::Cookies->new;
 $ua->cookie_jar($cookie_jar);

Nie da się na przykład wysłać cookie przez skrypt uruchamiany jako SSI.

14. Jak identyfikować oglądacza WWW?

Chodzi o mechanizm sesji i stosuje się tu albo cookies, albo do URL dokleja identyfikator (coś w stylu "&id=564534").

15. Czy jest wbudowany mechanizm sesji?

Służy do tego moduł Apache::Session.

16. Jak wysłać po sobie kilka stron?

Chodzi o technikę wysyłania wielu stron przez serwer bez powtarzania żądań ze strony przeglądarki. Należy użyć modułu CGI::Push.

17. Co to są wstawki SSI i jak ich używać?

Apache i większość innych serwerów WWW pozwala włączać w treść stron WWW wyniki działania skryptów CGI znajdujących się na lokalnym serwerze. Jeżeli używamy apache'a w pliku ".htaccess" lub httpd.conf winny być następujące linie:

 AddType text/html .shtml
 AddHandler server-parsed .shtml

lub (w starszych wersjach Apache'a)

 AddType text/x-server-parsed-html .shtml

oraz (dla pliku httpd.conf w zasięgu sekcji <Directory /ścieżka/do/katalogu>)

 Options +Includes +ExecCGI

Dzięki nim (opcja Includes) Apache będzie przeglądał pliki o rozszerzeniu ".shtml" w poszukiwaniu tagów typu

 <!--#bla bla bla -->  

To, co wygenerują wywołane przez SSI skrypty nie jest już interpretowane: wywołań SSI nie można zagnieżdzać.

Istnieją dwie zasadnicze metody odwoływania się do SSI: exec i include. Ta druga jest zalecana: jest bezpieczniejsza, a skryptom wywoływanym (dzięki opcji ExecCGI) w ten sposób można przekazywać parametry bezpośrednio, poprzez URL np.

 <!--#include virtual="skrypt.cgi?parametr=wartosc" -->

Aby przekazać parametry do SSI należy napisać plik.shtml?param=wart Dzięki tej formule wszystkie parametry powinny być widoczne we wszystkich odwołaniach SSI. Parametry będą również widoczne po ich ustawieniu w kodzie HTML tagiem

 <!--#set var="nazwa_zmiennej" value="wartosc" -->

Więcej informacji w dokumentacji do Apache np. http://sunsite.icm.edu.pl/pub/www/apache/docs/mod/mod_include.html

18. Jak uruchamiać CGI pod DOS/Windows?

W pierwszej linijce skryptu ma być #!/Perl/bin/perl, o ile perl.exe jest w ścieżce do wykonywania, co mozna sprawdzić pisząc w linii komend

 perl.exe skrypt.pl

Inna wersja to #!C:\perl\bin\perl.exe -w lub #!C:\perl\bin\wPerl.exe

Zobacz też punkt o testowniu skryptów.

19. Jak automatycznie wypełnić formularz?

http://www.stonehenge.com/merlyn/WebTechniques/col43.html

20. Jak pisać licznik?

 open( F, "+<$czas.dat" ) or die "open: $!";
 my $l = <F>;
 seek F, 0, 0;
 print F ++$l;
 close F;

Należy także uwzględnić zagadnienie równoczesności dostępu poprzez ograniczanie dostępu do pliku (patrz dział pliki).

21. Jak pisać książkę gości?

1. Skorzystanie z metody POST

2. Jeśli wpisy do księgi gości pojawiają się na stronie już w postaci gotowego pliku html'a (strona nie jest generowana w locie na podstawie bazy danych) to sprawdź koniecznie ustawienie serwera czy nie jest on parsowany (AddHandler server-parsed "tu rozszerzenie pliku z księgą gości"). Jeśli tak, to np. jakiś wesołek jako wpis wstawi wredną dyrektywę SSI i "obejrzy sobie swój wpis w książce". To co zobaczy zależy od pomysłowości autora i stopnia zabezpieczenia serwera, ale na pewno nie będzie to wpis.

3. Uwaga jeśli wpisy stają się w pewnym miejscu skryptu parametrami poleceń systemowych.

4. Uwaga jeśli wpisy stają się w pewnym miejscu skryptu choćby fragmentami ścieżek do plików. (3 i 4 - naprawdę niebezpieczne gdy skrypt chodzi z wyższymi uprawnieniami niż nobody)

5. Sprawdzenie wielkości przesyłanych danych - to chyba oczywiste

6. Sprawdzenie wpisów pod kątem zawartości tagów html'owych (i ich zamiana)

22. Jak wykonać zadania systemowe przez WWW?

Należy tu zwracać szczególną uwagę na bezpieczeństwo. Można to zrealizować następująco. Dane z formularza wysyłane są do skryptu w perlu, który z tych danych robi plik tymczasowy. Potem co np. 5 minut uruchamia się z crona drugi skrypt (man crontab), który czyta dane z plików i wykonuje zadane prace. W pełni bezpieczne rozwiązanie (tylko ten drugi skrypt działa z uprawnieniami roota). Frazy kluczowe: wwwadduser, TACACS, RADIUS.

23. Co to jest mod_perl?

Modperl to po prostu kompilator/interpreter perla wbudowany w serwer HTTP. Jeżeli używasz CGI w perlu, to przy każdym pobraniu strony serwer musi uruchomić perla (jako zewnętrzny program), który wczytuje skrypt, kompiluje i wykonuje. Jeżeli używasz zamiast tego modperla, wtedy serwer (tzn. ten wbudowany w serwer perl) od razu wczytuje skrypt. Mało tego - po skompilowaniu zwykle trzyma sobie taką wersję w pamięci i tylko wykonuje - więc działa to znacznie szybciej.

Mod_perl polega właśnie na tym, że skrypt jest uruchamiany raz, a potem kolejne zapytania obsługuje "w pętli". Jeżeli gdzieś otwierasz połączenie do bazy, to zostanie ono otwarte. Jeżeli gdzieś coś bindujesz, to pozostanie zbindowane. Pisząc pod mod_perla należy o tym pamiętać i robić na końcu swojego skryptu "porządki", tak żeby kolejne wywołanie mogło poprawnie działać.

Przy użyciu modperla nie tylko możesz pisać szybkie CGI, ale też robić znacznie więcej - za pośrednictwem specjalnego API masz dostęp do "bebechów" serwera HTTP (tzn. Apache). Służy też do pisania modułów do Apacha w perlu. Możesz użyć np. Apache::Registry - i wtedy piszesz normalne CGI (przy użyciu modułu CGI albo dowolnego innego do standardowych CGI), tyle że jest ono uruchamiane przez modperla więc działa znacznie szybciej (odpada czas kompilacji) - 20 do kilkuset razy.

Mod_perl lubi być pamięciożerny, co przy wielu jednoczesnych serwerach Apache bywa często problemem.

Instalacja: http://perl.apache.org/guide/install.html

 http://www.pckurier.pl/archiwum/artykuly/kozinski_maciej/2001_03_74/list4.asp
Dokumentacja: http://perl.apache.org/ Apache z mod_perl i in.: http://www.apachetoolbox.com/

 perldoc Apache, Apache::Registry, Apache::PerlRun

24. Jak zacząć z FastCGI?

Działa ono w punktu widzenia perla podobnie do mod_perla.

Do serwera WWW musi być dołączony moduł FastCGI. W pliku httpd.conf musi być linia np.: AddHandler fastcgi-script .fcgi, dzięki temu wszystkie skrypty z rozszerzeniem fcgi powinny być wykonywane przez FastCGI.

Skrypty FastCGI nieco różnią się od zwykłych CGI. Musisz stosować moduł FCGI (lub jakąś "nakładkę" na niego).

W FastCGI jest tak: serwer wcześniej uruchamia skrypt CGI, który jest napisany w specjalny sposób, po wykonaniu inicjalizacji otwiera gniazdko i oczekuje na polecenia. W momencie gdy przyjdzie request obsługiwany przez ten skrypt, serwer łączy się ze skryptem, przesyła mu parametry i czeka na odpowiedź.

Dzięki temu, po pierwsze znika nam czas potrzebny na uruchomienie perla, wczytanie i skompilowaniu skryptu, po drugie - możemy wykonać czasochłonne operacje (jak np. połączenie do bazy) w części inicjalizacyjnej.

Najprościej zmienić wszędzie w programie CGI na CGI::Fast. Ale to niespecjalnie przyspieszy działanie programów. Żeby to miało sens, trzeba skrypt przepisać tak:

 #!/usr/bin/perl
 use CGI::Fast;

 # tutaj inicjalizacja - to co wystarczy zrobić raz
 $dbh = DBI::connect ...
 $sth = $dbh->prepare( "SELECT ... WHERE x = ?" );

 while( my $q = new CGI::Fast ) {
   # A tutaj obsługa każdego kolejnego requestu, np.:
   print "Content-type: text/plain\n\n";
   print "OK\n";
 }

W momencie gdy przychodzi nowy request do serwera HTTP skrypt zazwyczaj jest już w miejscu "new CGI::Fast" więc może bardzo szybko obsłużyć zapytanie. Ponowne przejście do tego warunku w pętli powoduje najpierw zakończenie poprzedniego requestu i wysłanie wyników do przeglądarki, a następnie oczekiwanie na kolejny request.

Jak widać, requesty są kolejkowane i obsługiwane sekwencyjnie. W praktyce można konfigurować serwer tak, aby uruchamiał więcej niż jeden proces FastCGI, w ten sposób możemy obsługę bardziej "zrównoleglić".

25. Jak połączyć Perla z HTML-em?

Dobrym pomysłem jest wykorzystanie mod_perla oraz jakiegoś modułu. Najcześciej używanym jest chyba HTML::Template oraz dość zaawansowany HTML::Mason. Inne (choć na pewno nie wszystkie) to: HTML::EmbPerl, HTML::EP, HTML::DynamicTemplate, CGI::FastTemplate, Taco::Template, Text::BasicTemplate, Text::Template, Text::SimpleTemplate oraz Template::Toolkit (podobno dość przyjemny).

Przegląd szablonów dostępny jest pod adresem http://perl.apache.org/features/tmpl-cmp.html

Przykład template.tmpl:

 <html>
  <head>
   <title><TMPL_VAR NAME=title></title>
   <meta http-equiv="Content-type" content="text/html; charset=iso-8859-2" \>
  </head>
  <body bgcolor="#ffffff">
   <center><h1><TMPL_VAR NAME=title></h1></center>
   
<TMPL_VAR NAME=descr>
</body> </html>

i fragment kodu w perlu:

 use HTML::Template;

 $tmpl = new HTML::Template(filename => "template.htmp")
 $tmpl->param(title => "Test");
 $tmpl->param(descr => "Testowa strona");
 $tmpl->output();
 $tmpl->clear_params();

Perl FAQ | RecentChanges | Preferences
This page is read-only | View other revisions
Last edited June 27, 2006 8:46 am by kujon.kt.agh.edu.pl (diff)
Search:
Strona znajduje się na serwerze KT AGH.