www.agora.ro

Hello World!

Introducere în CGI

Florin Sabău

Acest articol își propune să fie o inițiere în tainele CGI, o interfață cu ajutorul căreia poate fi realizată interactivitatea între un server și calculatorul pe care sunt vizualizate paginile Web de pe serverul respectiv.

Mulțumită World Wide Web-ului (WWW), aproape oricine poate pune la dispoziția celorlalți informații într-o formă vizuală plăcută. Probabil că ați navigat de multe ori pe Web și v-ați dat seama că acronimele teribile ca HTTP sau HTML nu sunt altceva decât un mod complicat de a spune Web și modalitatea prin care se prezintă informația pe Web.

Web-ul s-a dovedit a fi un mediu propice pentru distribuirea informației așa cum se poate observa din imensa popularitate de care se bucură, ca și de creșterea sa exponențială din ultimii ani. Deși unii nu au fost convinși de utilitatea Web-ului și au pus creșterea sa pe seama publicității care i se face, acesta este, fără îndoială, o unealtă importantă în accesarea unei palete variate de informații.

Deși pune la dispoziția utilizatorului o interfață foarte prietenoasă (bazată pe conceptul de hypermedia), există și alte forme de a distribui eficient date și informații. De exemplu, servicii ca FTP (File Transfer Protocol) și Gopher existau cu mult înaintea apariției World Wide Web-ului. De asemenea, e-mail-ul a reprezentat principala modalitate de comunicare pe Internet încă de la începuturile acestei rețele. Atunci, cărui fapt se datorează popularitatea Web-ului? Nu poate fi ignorat faptul că aspectul multimedia a contribuit mult, dar factorul determinant a fost interactivitatea sa. Pe lângă oferta de informații, fără capabilitatea de a primi informații de la utilizatori, Web-ul ar fi un mediu complet static, informația ar fi disponibilă doar în formatul definit de autor. Astfel în loc ca utilizatorul să fie nevoit să răsfoiască mai multe documente pentru a găsi informația dorită (ca și când ar avea în față o carte sau un dicționar), ar fi de preferat ca utilizatorul să testeze câteva cuvinte cheie care să specifice subiectul de interes, iar serverul Web să se ocupe de căutarea informațiilor utile.

Deși serverul Web poate transmite și primi date, el are o funcționalitate limitată. În mod normal, el nu știe ce să facă cu informațiile pe care utilizatorul le introduce și de cele mai multe ori le ignoră. Pentru a spori capabilitățile serverului Web, acesta trebuie "învățat" și aici intră în scenă CGI.

Ce este CGI?

Common Gateway Interface (CGI) este o interfață între serverul Web și utilizator.

La un nivel teoretic, CGI sporește funcționalitatea serverului, prin posibilitatea sa de a interpreta datele introduse de utilizatorul care accesează serverul și de a returna informații în funcție de aceste date. Practic, CGI este o interfață care-l ajută pe programator să scrie programe care să comunice foarte ușor cu serverul.

CGI pune la dispoziția programatorului o soluție simplă și portabilă pentru a îndeplini aceste deziderate. Există un protocol care definește un mod standard în care programele pot să comunice cu serverul Web. Astfel, fără prea multe cunoștințe din domeniul rețelelor sau al arhitecturii serverelor, se pot scrie programe în orice limbaj de programare dacă se generează un cod executabil care să ruleze pe respectivul server.

Comunicarea între program și server se realizează prin intermediul intrării și ieșirii standard (standard input/output). Aceasta înseamnă că tot ceea ce trebuie să știm pentru a scrie un program CGI este să citim date de la intrarea standard și să tipărim date la ieșirea standard în limbajul de programare favorit.

Cu excepția interpretării intrării și ieșirii standard, proiectarea și implementarea unei aplicații CGI sunt aproape echivalente cu proiectarea și implementarea oricărei alte aplicații. De exemplu, dacă vrem să scriem un program de tip "Hello World!", nu trebuie decât să folosim o funcție de tipul printf(), respectând formatul standard definit pentru programele CGI.

Ce limbaj să folosesc?

Datorită faptului că CGI este o interfață comună (common interface), nu există limitări asupra limbajului de programare care poate fi folosit. De fapt, poate fi folosit orice limbaj care oferă suport pentru:

  • tipărire la ieșirea standard;
  • citire de la intrarea standard;
  • citirea variabilelor de mediu (environment variables).

Limbajele se pot împărți în două mari categorii:

  • cele care compilează sursele programului într-un fișier obiect; din această categorie fac parte limbajele C și C++ (au ca avantaje un produs final de dimensiuni mici și foarte rapid la execuție, codul compilat este însă dependent de platformă)
  • cele care interpretează linie cu linie sursele programului; cel mai folosit limbaj de programare de acest tip este Perl (mai lente la execuție, dar sursele sunt portabile; există interpretoare de Perl pentru o varietate de platforme și sisteme de operare)

Care dintre cele două limbaje este mai bun? C sau Perl? Dacă doriți viteză la rulare probabil că veți alege C; în schimb, dacă doriți o paletă largă de funcții de procesare a textului sau doriți să scrieți repede un program CGI, probabil că Perl se va descurca mai bine. De asemenea, un factor important este și experiența anterioară dobândită cu unul dintre ele.

Pentru început vom folosi C datorită faptului că este foarte răspândit, existând versiuni pentru majoritatea platformelor și sistemelor de operare.

Având în vedere că nu toți cititorii au acces la un server Web și cum cele mai răspândite sisteme sunt cele pe care rulează Windows, pentru a încerca exemplele din acest articol recomandăm folosirea aplicației OmniHTTPd produsă de firma Omnicron. Această aplicație permite simularea comportamentului unui server, folosind un calculator obișnuit.

Primul program CGI

Programarea CGI se poate reduce la două sarcini: citirea informațiilor din programul de navigare și tipărirea informațiilor înapoi în programul de navigare.

Probabil că de multe ori, la accesarea unui site Web, ați fost nevoit să completați un formular cu datele dumneavoastră personale. În multe cazuri, toate aceste date, după ce se apasă butonul Submit (sau un alt buton care are același rol), sunt trimise de programul de navigare către un program CGI care rulează pe serverul Web. Acesta convertește informațiile într-un format cunoscut de el, le procesează și apoi trimite înapoi programului de navigare (și implicit utilizatorului) rezultatele; acestea pot fi, de exemplu, răspunsurile la o căutare complexă într-o bază de date stocată pe server. Cu alte cuvinte, programarea CGI constă în înțelegerea modului în care programul de navigare transmite datele furnizate de utilizator către server și a modului în care programul de navigare se așteaptă să primească rezultatele de la server.

Pentru început vom vedea cum se poate scrie în C un program CGI foarte simplu (de tip "Hello World!"), urmând ca apoi să explicăm fiecare linie în detaliu.

Va trebuie să introduceți codul sursă și să-l salvați sub numele HELLO.C. Acest fișier trebuie compilat, iar fișierul executabil trebuie mutat în directorul cu programe CGI de pe server (de obicei /cgi-bin pe sistemele UNIX). Dacă nu aveți acces la un server Web dar ați instalat aplicația OmniHTTPd, veți muta executabilul în directorul c:\httpd\cgi-bin\. Pentru a vizualiza rezultatul deschideți programul de navigare preferat și introduceți URL-ul http://adresa_server_web/cgi-bin/hello.exe. Dacă folosiți aplicația OmniHTTPd sau orice altă aplicație care permite simularea comportamentului unui server Web veți introduce URL-ul http://localhost/cgi-bin/hello.exe.

Listing HELLO.C

#include <stdio.h>

void main(void) {

printf("Content-Type: text/html\r\n\r\n");

printf("<HTML>\n")

printf(" <HEAD>\n");

printf(" <TITLE>\n");

printf(" Hello, World!\n");

printf(" </TITLE>\n");

printf(" </HEAD>\n");

printf(" <BODY>\n");

printf(" <H1>");

printf(" Hello, World!");

printf(" </H1>\n");

printf(" </BODY>");

printf("</HTML>\n");

}

Sunt câteva lucruri care trebuie menționate. În primul rând, am folosit funcții simple de tipărire către stdout (standard output - ieșirea standard).

În al doilea rând, prima instrucțiune printf (cu parametrul "Content-Type: text/html") nu apare la ieșire în programul de navigare deoarece un program CGI poate returna orice fel de informație către programul de navigare care trebuie să cunoască tipul informației respective (o pagină HTML, o imagine grafică, o secvență audio etc.). Programul de navigare determină acest tip prin intermediul header-ului "Content Type:". În cazul nostru este vorba de o pagină HTML (text/html). Forma generală a acestui header este:

Content-Type: subtype/type

unde "subtype/type" este un tip MIME (Multipurpose Internet Mail Extensions) valid. Tabelul 1 prezintă câteva dintre aceste tipuri:

Tip MIME Descriere Tabelul 1

text/html HyperText Markup Language (HTML)

text/plain fișier text simplu

image/gif fișier grafic .GIF

image/jpeg fișier grafic .JPG

audio/basic fișier sunet .au

audio/x-wav fișier sunet .wav

Urmează apoi sursa paginii HTML propriu-zise. Trebuie remarcat faptul că header-ul și sursa sunt despărțite de o linie liberă ("\r\n").

Pentru a realiza programe CGI care să interacționeze cu utilizatorul trebuie să înțelegem mecanismul prin care programul de navigare trimite către programul CGI datele introduse de utilizator în formularele HTML.

Formularele HTML

Cele mai importante marcaje HTML din punctul de vedere al programatorului de CGI-uri sunt <FORM> și <INPUT>. Practic, folosind aceste două marcaje putem realiza orice tip de formular care să permită utilizatorului introducerea datelor în vederea prelucrării de către programul CGI. Nu vom realiza o prezentare exhaustivă a celor două marcaje, ci vom sublinia doar elementele mai importante.

Marcajul <FORM> este utilizat pentru a delimita, în cadrul fișierului HTML, porțiunea care este folosită de utilizator pentru a introduce date. Atributele marcajului specifică numele programului care va prelucra datele și locația sa (sub forma unui URL), tipul de codificare folosit și metoda cu care se face transferul datelor de intrare către programul CGI.

Sintaxa acestui marcaj este:

<FORM action="url" method=[post|get] enctype="...">

Atributul enctype nu este foarte important și de aceea este rar folosit. Este utilizat doar atunci când dorim să trimitem (upload) un fișier către server. Atributul action conține calea și numele programului CGI. După ce utilizatorul apasă butonul Submit, toate informațiile din formular sunt codificate și transmise către programul CGI prin una din metodele Post sau Get, selectată prin intermediul atributului method.

Marcajul <INPUT> este utilizat pentru a crea câmpuri de editare de text, butoane radio, butoane de selecție etc. Cea mai simplă formă a marcajului <INPUT> este:

<input type="tip">

unde tip poate lua valori ca:

  • text: un câmp de editare de text (un singur rând); se poate specifica numele acestui câmp (atributul name), dimensiunea prin atributul size, cât și lungimea maximă (în caractere) prin atributul maxlength;
  • submit: butonul care declanșează operația de codificare a informațiilor și trimitere a lor către programul CGI. În mod implicit are valoarea Submit Query, dar aceasta poate fi modificată prin intermediul atributului value;
  • reset: butonul a cărui selectare determină resetarea (ștergerea) tuturor câmpurilor;
  • radio: doar unul din mai multe astfel de butoane poate fi selectat la un moment dat. Atributul name este același pentru butoanele din aceeași categorie, variază doar atributul value. Pentru ca un astfel de buton să fie selectat implicit, se folosește atributul checked;
  • checkbox: un câmp cu două stări: selectat sau neselectat; numele și valoarea câmpului este trimisă către programul CGI doar dacă respectivul câmp este selectat; pentru a selecta implicit un astfel de câmp se folosește atributul checked;
  • hidden: acest câmp este invizibil și este folosit, de cele mai multe ori, pentru a reține informații de stare;
  • image: se comportă ca un buton Submit doar că încarcă o imagine (URL-ul fișierului care conține imaginea este indicat prin intermediul atributului src); prin efectuarea unui click pe imagine se transferă programului CGI și coordonatele x și y ale punctului deasupra căruia se află cursorul mouse-ului.
  • password: este identic cu text, cu excepția faptului că nu se văd caracterele introduse (acestea sunt înlocuite de caractere '*' - asterisc).

Metodele GET și POST

În momentul în care utilizatorul a terminat de introdus datele în formular și a apăsat butonul Submit, două tipuri de date sunt trimise către programul CGI: datele din formular și informații despre programul de navigare și despre server. Cele din cea de-a doua categorie sunt puse la dispoziția programului CGI prin intermediul variabilelor de mediu, în timp ce primele sunt disponibile ori printr-o variabilă de mediu (în cazul metodei GET), ori prin intermediul intrării standard (metoda POST).

Indiferent dacă un formular este transmis unui program CGI sau nu, orice astfel de aplicație primește informații privitoare la programul de navigare și la server prin intermediul variabilelor de mediu. Aceste informații includ:

  • locația programului de navigare în cadrul rețelei;
  • tipul programului de navigare și tipul de documente pe care acesta le poate citi;
  • numele și versiunea serverului (software) de Web care a apelat programul CGI;
  • instrucțiuni cu privire la modul în care trebuie interpretate datele trimise de programul de navigare.

În continuare vom da câteva exemple de astfel de variabile de mediu:

  • variabile generale - PATH, TEMP, variabile setate din autoexec.bat sau config.sys;
  • GATEWAY_INTERFACE - conține versiunea protocolului CGI folosit (de exemplu "CGI/1.1");
  • SERVER_SOFTWARE - numele software-ului care asigură servicii HTTP pe server;
  • SERVER_NAME - numele serverului Web;
  • SERVER_PROTOCOL - versiunea protocolului HTTP (de obicei "HTTP/1.0");
  • REMOTE_HOST - hostname-ul clientului;
  • REMOTE_ADDR - adresa IP a clientului;
  • REQUEST_METHOD - poate fi GET sau POST în funcție de metoda folosită;
  • PATH_INFO - calea către fișierul CGI relativă la directorul în care se află rădăcina site-ului Web;
  • PATH_TRANSLATED - calea completă la fișierul CGI;
  • QUERY_STRING - conține datele de intrare din formular transmise prin metoda GET; aceste date sunt codificate;
  • CONTENT_TYPE - conține un tip MIME care descrie modul în care sunt codificate datele de intrare (implicit are valoarea "application/x-www-form-urlencoded") și este identic cu atributul enctype al marcajului <form>;
  • CONTENT_LENGTH - conține lungimea datelor de intrare trimise către programul CGI. Este definită doar pentru metoda POST;
  • HTTP_ACCEPT - conține o listă a tipurilor MIME recunoscute de programul de navigare, separate prin virgulă;
  • HTTP_USER_AGENT - conține numele programului de navigare, versiunea și platforma pe care rulează. De obicei are forma: Program_de_navigare/Versiune (Sistem_de_operare);
  • HTTP_REFERER - conține URL-ul ultimei pagini vizitate; această variabilă poate fi folosită pentru a insera în pagina generată de programul CGI o legătură spre pagina anterioară.

Pentru a pune în aplicare cele prezentate până acum vom folosi o pagină HTML care conține un formular și un program CGI care va returna valorile tuturor variabilelor de mediu.

Documentul HTML care generează o astfel de pagină Web este următorul:

Listing FORMULAR.HTML

<html>

<head>

<title>

Un formular simplu

</title>

</head>

<body>

<form action='http://localhost/

cgi-bin/formular.exe' method=post>

<input type=text name='camp'

size=15 maxlength=5>

<br>

<input type=radio name=radio

value="primul" checked>

Primul buton <br>

<input type=radio name=radio

value="al_doilea">

Al doilea buton <BR>

<input type=checkbox name=check

value="unu" checked>

Unu <br>

<input type=checkbox name=check

value="doi" checked>

Doi <br>

<input type=password name=parol>

<br>

<input type=submit name='buton'>

<input type=reset name='reset'>

</form>

</body>

</html>

Fișierul sursă pentru script-ul CGI care afișează valorile variabilelor de mediu este următorul:

Listing FORMULAR.C

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

void main(void){

int l;

char *s;

char **p=environ;

printf("Content-Type: text/html\r\n\r\n");

while (*p)

printf("%s <BR>",*p++);

if (!strcmp(getenv("REQUEST_METHOD"),

"GET"))

printf("Ati introdus(GET): %s<BR>",

getenv("QUERY_STRING"));

else{

l=atoi(getenv("CONTENT_LENGTH"));

s=(char*)malloc(l);

scanf("%s",s);

printf("Ati introdus(POST): %s<P>",s);

printf("<CENTER><H3><A href='%s'> \

Inapoi </CENTER> <BR>",

getenv("HTTP_REFERER"));

}

}

Fișierul formular.html trebuie copiat în rădăcina site-ului Web (sau c:\httpd\htdocs dacă folosiți aplicația OmniHTTPd), iar fișierul FORMULAR.C trebuie compilat, apoi executabilul generat trebuie copiat în directorul cgi-bin (c:\httpd\cgi-bin pentru OmniHTTPd).

Din programul de navigare trebuie apelat URL-ul: http://siteweb/formular.html sau http://localhost/formular.html (dacă folosiți un server Web local - OmniHTTPd).

Codificarea URL

Probabil v-ați dat deja seama că, pentru a trimite date server-ului, programul de navigare le codifică după un anumit format.

Acest format se numește codificare URL (URL encoding). Aceasta a apărut datorită necesității de a codifica într-un anume fel URL-urile transmise prin e-mail, deoarece prin e-mail pot fi transmise doar primele 128 caractere ale setului de caractere ASCII. O parte din această codificare se referă la caracterele speciale cum ar fi Tab, Space, ghilimelele și, în general, caracterele extinse ale setului ASCII (cu numărul de ordine mai mare decât 127). De ce ar trebui să ne intereseze această codificare? Exsită două motive principale:

  • Anumite caractere trebuie codificate dacă sunt incluse într-un URL în cadrul atributului action al marcajului <form> sau oricare alt câmp trimis către programul CGI. Spațiile, caracterul procent (%), semnul de întrebare (?) sunt exemple de caractere speciale;
  • Toate datele trimise către programul CGI sunt codificate și de aceea trebuie înțeles mecanismul de codificare pentru a putea fi decodificate în cadrul scriptului CGI.

Referitor la primul aspect, codificarea se face astfel: atunci când programul de navigare întâlnește un caracter special, el îl înlocuiește cu un caracter procent (%) urmat de codul ASCII al caracterului respectiv în hexazecimal (cu două cifre). În tabelul 2 sunt prezentate caracterele speciale care au nevoie de codificare, precum și echivalentul lor hexazecimal.

Caracter Cod ASCII Tabelul 2

Tab 09

Space 20

" 22

( 28

) 29

, 2C

. 2E

; 3B

: 3A

< 3C

> 3E

@ 40

[ 5B

\ 5C

] 5D

^ 5E

` 60

{ 7B

| 7C

} 7D

~ 7E

Pe lângă aceste caractere speciale prezentate, alte câteva caractere trebuie codificate deoarece în mod normal au o semnificație specială pentru server:

  • Semnul de întrebare (?) se codifică prin %3F; dacă nu este codificat, caracterul indică începerea unui query;
  • Caracterul ampersand (&) se codifică prin %26; în forma necodificată este separator pentru câmpurile nume/valoare într-un query;
  • Caracterul slash (/) se codifică prin %2F; altfel este folosit pentru a despărți directoarele într-o cale;
  • Semnul egal (=) se codifică prin %3D; în forma necodificată desparte valorile nume și valore într-un query
  • Diezul (#) se codifică prin %23; este folosit ca referință la o etichetă dintr-un document;
  • Semnul procent (%) se codifică prin %25.

Referitor la al doilea tip de codificare folosit pentru datele introduse de utilizator într-un formular spre a fi transmise script-ului CGI, iată câteva reguli care stau la baza acestei codificări:

  • Datele sunt transferate ca perechi nume/valoare;
  • Aceste perechi sunt separate între ele prin caracterul ampersand (&);
  • Componenta nume este despărțită de valoare prin caracterul egal (=). Dacă nu a fost introdusă nici o valoare în formular dar acel câmp are o valoare prestabilită, aceasta va fi folosită. Dacă nu a fost introdusă nici o valoare și nici nu este definită o valoare prestabilită, atunci câmpul valoare este vid, dar o pereche nume/valoare este totuși transmisă;
  • Spațiile conținute în datele introduse în formular sunt caractere speciale și sunt transformate în caractere "+";
  • Caracterele speciale nu se pot folosi în URL, ele trebuie codificate;
  • Caracterele care au o semnificație specială pentru server (%, ? etc) trebuie codificate;
  • Caracterele sunt codificate prin convertirea la scrierea hexazecimală conform tabelului 2.

Florin Sabău este elev în clasa a XII-a la Liceul "Traian Lalescu" din Reșița. Poate fi contactat prin e-mail la adresa fsabau@cs.ro.

[cuprins]