CGI (Common Getway Interface) CGI zostało opracowane w 1993 roku przez NCSA jako technologia pozwalająca przeglądarce internetowej odbierać dane wygenerowane przez program uruchomiony przez serwer WWW CGI (Common Gateway Interface ) służy do łączenia zewnętrznych programów z serwisem WWW w celu tworzenia stron "w locie". Zamiast ograniczenia serwera WWW do maszyny udostępniającej przechowywane dokumenty (utworzone wcześniej), CGI umożliwia tworzenie stron błyskawicznie, na podstawie danych wprowadzonych przez użytkownika. Skrypty CGI mogą być używane do tworzenia różnego rodzaju aplikacji, począwszy od prostego przetwarzania formularzy, aż po zaawansowane bazy danych. Program (skrypt) CGI może być napisany w dowolnym języku programowania. CGI jest jednym z prostszych i wydajniejszych rozwiązań "dynamicznej komunikacji" z użytkownikiem. Protokół CGI definiuje standardowy sposób komunikacji z serwerem WWW oraz przeprowadzania konkretnych operacji. Programista ma właściwie dowolność przy wyborze języka od napisania skryptu CGI. Może być to Perl, C, C++, Pascal, zwykły plik wsadowy z UNIX a... Ważne, żeby taki język "potrafił" wypisać dane na standardowe wyjście (STDOUT). Serwer WWW uruchamiając skrypt przekazuje mu informacje: poprzez parametry wiersza poleceń (w przypadku wywołania skryptu z parametrami) poprzez zmienne środowiskowe, zawierające dane o serwerze, uruchomionym skrypcie, przeglądarce użytkownika; poprzez standardowe wejście (wyłącznie dla skryptów obsługujących formularze przy użyciu metody POST ) 27 października 2015 Strona 1
Standardowe zmienne środowiskowe CGI: Protokół HTTP HTTP (Hypertext Transfer Protocol) jest protokołem sieciowym służącym do transportu dokumentów (pliki HTML, pliki graficzne, strony generowane dynamicznie, itp.) udostępnianych przez serwery HTTP. HTTP jest protokołem tekstowym, opartym na TCP, zwykle wykorzystującym port komunikacyjny 80. Wykorzystuje model komunikacyjny typu klient-serwer. Klient HTTP nawiązuje połączenie sieciowe z serwerem HTTP i przekazuje mu komunikat zawierający żądanie HTTP. Serwer HTTP odpowiada na to żądanie wysyłając odpowiedź HTTP, zawierającą żądany dokument. Po dostarczeniu żądanego dokumentu serwer HTTP zamyka połączenie. URL (ang. Uniform Resource Locator) oznacza ujednolicony format adresowania zasobów (informacji, danych, usług) stosowany w Internecie i w sieciach lokalnych. http://pascal.ftj.agh.edu.pl/~grazyna/cgi-bin/przyklad5.cgi?wzor zapytanie Łańcuch zapytani (QUERY STRING) służy do przekazywania do skryptów dodatkowych parametrów. Może zawierać pary nazwa=wartość, poszczególne pary oddzielone są znakiem &. 27 października 2015 Strona 2
Cykl żądania i odpowiedzi Chociaż żądanie i odpowiedź zawierają różne informacje struktura wiadomości http jest taka sama Żądanie przeglądarki http://pascal.ftj.agh.edu.pl/~grazyna/cgi-bin/przyklad2.cgi Odpowiedź serwera WWW 27 października 2015 Strona 3
Skrypty CGI: Skrypty CGI uruchamiane są przez serwer WWW, a więc najczęściej wykonują się z uprawnieniami, które zostały przyznane serwerowi WWW. Rodzi to różne niebezpieczeństwa dla systemu operacyjnego w których działa zarówno serwer WWW jak i skrypt CGI. Z tego też powodu, administratorzy zezwalają na uruchamianie aplikacji CGI z odpowiednich katalogów, dla których przygotowano odpowiednie zabezpieczenia. Na serwerze Pascal skrypty CGI mogą być uruchamiane z katalogu "cgi-bin" który znajduje się w katalogu "public_html" użytkownika. Dodatkowo należy nadać plikom uprawnienia dające możliwość uruchomienia przez serwer WWW. Skrypty CGI umieszczamy w katalogu login_name/public_html/cgi-bin Zadaniem aplikacji (skryptu) działającego poprzez interfejs CGI jest przygotowanie pliku zawierającego dokument HTML oraz informacyjne wiersze nagłówkowe protokołu HTTP. Informacja ta jest przesyłana poprzez plik STDOUT z aplikacji do serwera WWW. Serwer WWW po odebraniu informacji dodaje pozostałe wiersze nagłówkowe łącznie z pierwszym wierszem informującym o wersji protokołu HTTP i kodzie odpowiedzi. Odpowiedzią skryptu powinien być dokument, który serwer ma odesłać do przeglądarki użytkownika. Poprawny plik zawiera nagłówek np. Content-Type: podtyp/typ który oddzielony jest pustą linią od właściwej treści dokumentu. Przykładowa odpowiedź generowana przez aplikację CGI przedstawiona została poniżej. Do określenia rodzaju danych w nagłówku należy użyć prawidłowego uniwersalnego rozszerzenia poczty elektronicznej (ang. Multipurpose Internet Mail Extension MIME). Najczęściej wstępujące typy MIME to: 27 października 2015 Strona 4
W przypadku niepoprawnej konstrukcji odpowiedzi wygenerowanej przez aplikację serwer WWW wyśle do przeglądarki komunikat o wewnętrznym błędzie serwera (kod 500 - Intrernal Server Error). Skrypt CGI wykorzystujący polecenia powłoki systemu Linux. #!/bin/sh echo Content-type: text/html echo echo "<html><head><title>skrypt w shell'u</title></head>" echo "<body>" echo "<h2>zalogowani uzytkownicy w systemie:</h2>" echo "<pre>" who echo "</pre>" echo "</body>" echo "</html>" Skrypt drukuje zmienne środowiskowe dostępne z poziomu powłoki bash #!/bin/bash echo "Content-type: text/html" echo "" echo "<html>" echo "<head>" echo "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">" echo "<title>environment Variables</title>" echo "</head>" echo "<body>" echo "Environment Variables:" echo "<pre>" /usr/bin/env echo "</pre>" echo "</body>" echo "</html>" exit 0 27 października 2015 Strona 5
Skrypt w języku perl drukujący zmienne środowiskowe dostępne w tablicy asocjacyjne $ENV #!/usr/bin/perl -wt print <<KONIEC_HTML; Content-type: text/html <html> <head><title>informacje o serwerze</title></head> <body> <h1>parametry serwera</h1> <hr><br /> <table> <tr><td>nazwa uzytkownika</td> <td>$env{user}</td></tr> <tr><td>sciezka</td> <td>$env{pwd}</td></tr> <tr><td>terminal</td> <td>$env{term}</td></tr> </table> </body> <html> KONIEC_HTML Skrypt w języku perl wyświetlający wszystkie zmienne środowiskowe serwera WWW zawarte w tabeli $ENV #!/usr/bin/perl print "Content-type: text/plain\n\n"; foreach $var (sort(keys(%env))) { $val = $ENV{$var}; $val =~ s \n \\n g; $val =~ s " \\" g; print "${var}=\"${val}\"\n"; Skrypt znajdujący wzorzec podany w QUERY_STRING w plikach w katalogu bieżącym #!/bin/sh echo "Content-Type: text/html" echo echo "<html><body>" echo "<p>" echo "skrypt znajdujący wzorzec podany w QUERY_STRING w plikach w katalogu bieżącym" echo "<p>" SLOWO=`echo "$QUERY_STRING" sed s/^.*=//` echo "Poszukiwanie $SLOWO... w `pwd`" echo "<ul>" grep -rli "$QUERY_STRING" * while read f do echo "<li><a href=\"$f\">$f</a></li>" done echo "</ul>" echo "OK" echo "</body></html>" http://pascal.ftj.agh.edu.pl/~grazyna/cgi-bin/przyklad5.cgi?wzor 27 października 2015 Strona 6
Duże możliwości przed projektantami stron WWW daje możliwość wykorzystania języka C/C++ w serwisach WWW. Dostęp do zmiennych środowiskowych w języku C otrzymuje programista poprzez funkcję getenv() zawartą w bibliotece "stdlib.h", natomiast poprzez obsługę standardowego pliku wejściowego "STDIN" otrzymujemy dostęp do ciała żądania (metoda POST). W przykładzie umieszczonym poniżej zaprezentowano odczyt zmiennych środowiskowych zrealizowane w języku C../* Program nalezy skompilowac i udostepnic jego wersje wykonywalna gcc -o env_c.cgi env_c.c */ #include <stdio.h> #include <stdlib.h> int main( void ) { /* generaja naglowka czastkowego */ printf("content-type: text/html\n\n"); /* Wydruk kodu HTML na STDOUT */ printf("<html><head><title>przyklad 1</title></head>\n"); printf("<body><h2>przyklad 1</h2><br>\n"); /* Pobranie informacji o kliencie */ printf("nazwa serwera klienta: %s<br>\n", getenv("remote_host") ); printf("adres IP klienta: %s<p>\n", getenv("remote_addr") ); /* dane serwera przechowywane w zmiennych srodowiskowych */ printf("nazwa serwera: %s<br>\n", getenv("server_name") ); printf("oprogramowanie na serwerze: %s<br>\n", getenv("server_software") ); printf("protokol serwera WWW: %s<br>\n", getenv("server_protocol") ); printf("numer portu na serwerze: %s<br>\n", getenv("server_port") ); printf("</body>\n</html>\n"); return(0); } Obsługa formularzy w technologii CGI Formularze HTML jest to interfejs użytkownika, który umożliwia wprowadzanie danych i przekazywanie ich do serwera WWW. W ramach aplikacji WWW formularze realizują następujące funkcjonalności: przekazywanie danych użytkownika do aplikacji i sterowanie działaniem aplikacji. Dane z formularza przeglądarka umieszcza w żądaniach do serwera WWW. I tak w żądaniu GET dane są zawarte w łańcuchu zapytania będącego częścią URL'a w wierszu żądania. W przypadku metody POST dane są zawarte w treści żądania HTTP. Przesyłane dane są kodowane. Domyślnym sposobem kodowania danych jest "application/x-www-form-urlencoded". Możliwe jest też kodowanie "multiform/form-data", stosowane w przypadku formularzy, które umożliwiają przesyłanie plików na serwer WWW. 27 października 2015 Strona 7
Przesyłane dane z formularza przeglądarka łączy w pary nazwa=wartość, natomiast poszczególne pary łączone są przy pomocy łącznika & i przesyłane do serwera WWW w następujący sposób: get1=aaa&get2=bbb&get3=ccc Uwaga. W czasie kodowania znaki specjalne zastępowane znakiem % i dwucyfrową liczbą szesnastkową. Znaki spacji zastępowane są znakami plus. 27 października 2015 Strona 8
Metoda GET i POST 27 października 2015 Strona 9
27 października 2015 Strona 10
żądanie odpowiedź Na początek wykorzystamy skrypt w perlu do przetwarzania danych przesłanych na serwer zgodnie z metodą GET i POST protokołu HTTP. Poniżej przykład formularza i odpowiedni skrypt w języku perl przetwarzający dane przesłane z prezentowanego formularza. <html> <head> <title>test CGI</title></head> <body> <fieldset> <legend>form - method=get</legend> <form action="cgi-bin/read.cgi" method="get"> <input type="text" name="get1"><br> <input type="text" name="get2"><br> <input type="password" name="get3" ><br> <input type="submit"> </form> </fieldset> <fieldset> <legend>form - method=post</legend> <form action="cgi-bin/read.cgi" method="post"> <input type="text" name="post1"><br> <input type="text" name="post2"><br> <input type="password" name="post3" ><br> <input type="submit"> </form> </fieldset> </body> </html> 27 października 2015 Strona 11
Skrypt w perlu dekodujący przesłane dane z formularza #!/usr/bin/perl # Program przetwarzajacy formularz # Generowanie naglowka HTTP print "Content-type: text/html\n\n"; # Generowanie dokumentu HTML print "<html><head>\n"; print "<title> Display query string data </title></head> \n"; print "<body>\n"; # Rozpoznanie metody przeslania danych przez formularz $request_method = $ENV{'REQUEST_METHOD'}; if ($request_method eq "GET") { $query_string = $ENV{'QUERY_STRING'}; print " Metoda przeslania formularza - GET <br><hr>" ; } elsif ($request_method eq "POST") { read(stdin, $query_string, $ENV{'CONTENT_LENGTH'}); print " Metoda przeslania formularza - post <br><hr>" ; } else { print "Error - request method is illegal \n"; } # Podzial "query string" na pare wartosci "name=value" @name_value_pairs = split(/&/, $query_string); foreach $name_value (@name_value_pairs) { ($name, $value) = split (/=/, $name_value); print "Para 'name=value' zawiera nastepujace dane: $name, $value \n<br>"; } print "</body> </html> \n"; Odczyt danych z wiersza żądania dla metody GET zrealizowane w języku C. #include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { char *ptr; /* Tworzenie naglowka odpowiedzi */ printf("content-type: text/html\n\n"); /* Drukowanie kodu HTML na STDOUT */ printf("<html><head><title>jezyk C</title></head>\n"); printf("<body><h2>obsluga zadania GET</h2>\n"); /* Czytanie zmiennej srodowiskowej - QUERY_STRING */ printf("informacja przeslana w zadaniu: %s<p>\n", getenv("query_string") ); /* Wyszukanie zawartosci zmiennej */ ptr = strstr( getenv("query_string"), "=" ); ptr = ptr + 1; printf("hello %s!<br>\n", ptr ); printf("</body>\n</html>\n"); return(0); } 27 października 2015 Strona 12
Odczyt danych z wiersza żądania dla metody POST zrealizowane w języku C. #include <stdio.h> #include <stdlib.h> #define MAXLEN 80 int main(void) { char *lenstr; char input[maxlen]; long len; printf("%s%c%c\n","content-type:text/html;charset=iso-8859-2",13,10); printf("<title>response</title>\n"); lenstr = getenv("content_length"); if(lenstr == NULL sscanf(lenstr,"%ld",&len)!=1 len > MAXLEN) printf("<p>error in invocation - wrong FORM probably.</p>"); else { fgets(input, len+1, stdin); printf("\n %s",input); } return 0; } Prosty przykład prezentujący odbiór danych przesłanych z formularza w ramach skryptu powłoki systemu Linux. #!/bin/bash echo "Content-type: text/html" echo "" echo "<html>" echo "<head><title>test</title></head>" echo "<body>" echo "<h1>test for Bash CGI-Scripting</h1>" echo "<h2>post values from Standard-In</h2>" echo "<pre>" read -n $CONTENT_LENGTH QUERY_STRING_POST echo $QUERY_STRING_POST echo "</pre>" echo "<h2>environment</h2>" echo "<pre>$(env)</pre>" echo "</body>" echo "</html>" 27 października 2015 Strona 13
Generowanie grafiki w skryptach CGI Przedstawiony poniżej skrypt tworzy dynamicznie plik graficzny w standardzie png i przesyła do przeglądarki. #!/usr/bin/perl -wt use strict; use CGI; use GD::Graph::pie; my $q = new CGI; my $graph = new GD::Graph::pie( 300, 300 ); #my @data = read_data(); my @data = (['Paris','Frankfurt','London'], [7309,5322,9719] ) ; $graph->set( title => "Pie: total orders", transparent => 1, "3d" => 0, ); my $gd_image = $graph->plot( \@data ); print $q->header( -type => "image/png", -expires => "-1d" ); binmode STDOUT; print $gd_image->png; Wykorzystanie szablonów w perl'u Technologia szablonów umożliwia oddzielenie logiki aplikacji od skryptu HTML służącego do prezentacji na stronie WWW. W poniższym przykładzie przedstawiono wykorzystanie biblioteki HTML::Template w ramach aplikacji w języku perl. W skrypcie obliczane są odpowiednie wartości, które następnie przenoszone są do szablonu. Oddzielenie logiki od warstwy prezentacyjnej umożliwia tworzenie aplikacji przez niezależnych projektantów. Skrypt w perlu #!/usr/bin/perl use strict; use HTML::Template ; use constant PLIK_SZABLONU => "templates/curr_time.tmpl"; my $szablon = new HTML::Template ( filename => PLIK_SZABLONU ); my $czas = localtime ; $szablon->param ( current_time => $czas ) ; print "Content-type: text/html\n\n", $szablon->output ; Odpowiedni plik szablonu dla powyższego skryptu. <html> <head> <title>biezacy czas</title> </head> <body> <h1>biezacy czas</h1> <p>witamy, obecnie mamy <TMPL_VAR NAME="current_time">.</p></body></html> 27 października 2015 Strona 14