0% au considerat acest document util (0 voturi)
89 vizualizări70 pagini

Program Are Perl

Documentul prezintă limbajul de programare Perl, inclusiv caracteristicile sale generale, disponibilitatea și documentația, precum și o trecere în revistă a elementelor cheie ale limbajului.

Încărcat de

Ady Andyy
Drepturi de autor
© Attribution Non-Commercial (BY-NC)
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca PDF, TXT sau citiți online pe Scribd
0% au considerat acest document util (0 voturi)
89 vizualizări70 pagini

Program Are Perl

Documentul prezintă limbajul de programare Perl, inclusiv caracteristicile sale generale, disponibilitatea și documentația, precum și o trecere în revistă a elementelor cheie ale limbajului.

Încărcat de

Ady Andyy
Drepturi de autor
© Attribution Non-Commercial (BY-NC)
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca PDF, TXT sau citiți online pe Scribd
Sunteți pe pagina 1/ 70

Sabin Corneliu Buraga

Introducere n Programare Perl

2005

n loc de prefa

Acest material realizeaz o prezentare general a limbajului de programare Perl, insistnd asupra realizrii de script-uri Perl n contextul programrii Web pe partea de server via paradigma CGI (Common Gateway Interface). De asemenea, se prezint o serie de exemple de programe Perl i diverse propuneri de proiecte pentru a fi implementate de cititor. Lucrarea de fa se bazeaz, n cea mai mare msur, pe cartea S. Buraga et al., Programare Web n bash i Perl (include i un CD), Editura Polirom, Iai, 2002: http://www.infoiasi.ro/~cgi/. Pentru aprofundarea limbajului Perl, cititorul este ncurajat s consulte resursele bibliografice. Mai mult, poate vizita situl autorului: http://www.infoiasi.ro/~busaco/. Ateptm reacii i opinii la adresa e-mail [email protected].

1. Prezentare general a limbajului Perl


Pentru nceput, vom enumera cteva dintre caracteristicile specifice limbajului Perl. 1.1 Generaliti Creat iniial pentru prelucrarea sofisticat a informaiilor textuale, Perl (Practical Extraction and Report Language) l are ca printe pe Larry Wall, n decursul timpului la dezvoltarea limbajului contribuind i ali numeroi programatori. Distribuit gratuit, Perl a devenit favoritul administratorilor de sistem i al programatorilor de aplicaii Web, ns poate fi utilizat asemeni altui limbaj general. Ca i Linux, Perl a crescut n mediul prielnic al Internetului, varianta curent a limbajului fiind 5. Pe data de 18 decembrie 2005 se mplinesc 18 ani de la apariia limbajului. n curs de dezvoltare este versiunea Perl 6 a limbajului. Iniial, limbajul a fost conceput special pentru mediile UNIX, mprumutnd o serie de faciliti oferite de shell-urile i utilitarele standard i pstrnd filosofia de baz a UNIXului, dar n prezent Perl este disponibil pentru toate platformele actuale (e.g. Mac OS, Windows sau OS/2). n proiectarea limbajului s-au avut n vedere urmtoarele principii: lucrurile simple s se poat realiza uor, iar cele complexe s nu fie imposibil de implementat;

exist mai multe modaliti de realizare a unui program, n funcie de gradul de cunoatere a limbajului de ctre dezvoltatorul acelui program.

Drept caracteristici importante ale limbajului se pot enumera:

modularitatea

Perl ofer suport pentru mai multe paradigme de programare, ca de exemplu cea procedural i cea orientat-obiect; limbajul poate fi extins prin intermediul aanumitelor module, punndu-se la dispoziie un numr impresionant de module standard;

portabilitatea

Programele Perl se pot executa fr modificri pe orice platform;

expresivitatea i puterea

Limbajul dispune de mecanisme puternice pentru manipularea datelor, prin intermediul expresiilor regulate i a tablourilor; de asemenea, Perl poate fi folosit ca limbaj de sistem pentru lucrul cu entiti ale sistemului de operare (fiiere, dispozitive, procese, socket-uri);

viteza de dezvoltare a aplicaiilor

Ciclul compilare-execuie-depanare se poate realiza i itera rapid; Perl nu ofer un interpretor clasic, ci un compilator-interpretor. Fiind gratuit i posednd numeroase mijloace de documentare online, Perl poate fi folosit n special pentru dezvoltarea rapid de aplicaii de administrare a sistemului de operare i destinate Web-ului, reprezentnd un mediu ideal pentru conceperea script-urilor CGI. Mai mult, anumite servere Web (e.g., Apache) includ interpretoare Perl interne. 1.2 Disponibilitate i documentaii Mediul Perl se poate obine de pe Internet, via FTP sau HTTP, prin intermediul locaiilor CPAN (Comprehensive Perl Archive Network). Principala surs este ftp://ftp.funet.fi, dar se pot folosi i alte locaii, listate la http://www.perl.com/CPAN/. De asemenea, orice distribuie actual de Linux include interpretorul i manualele standard Perl. Pentru Windows, platforma Perl cea mai popular este ActivePerl, disponibil i pe CD-ul volumului S. Buraga et al., Programare Web n bash i Perl, Polirom, Iai, 2002: http://www.infoiasi.ro/~cgi/. Pentru a genera codul executabil al interpretorului Perl din sursele preluate din Internet, pentru un mediu UNIX (Linux) va trebui s scriem urmtoarele linii de comenzi de la prompt-ul sistemului, ca utilizatori cu drepturi de root:
(infoiasi)$ (infoiasi)$ (infoiasi)$ (infoiasi)$ (infoiasi)$ ./configure # pentru configurare automata ./Configure # pentru configurare manuala make make test make install

Perl include o serie de documentaii online care pot fi parcurse prin intermediul binecunoscutei comenzi man (ncercai, de exemplu, man perl). Pentru anumite detalii sau documentaii referitoare la modulele Perl, se poate folosi comanda perldoc. Astfel, dac dorim s aflm amnunte despre funcia standard Perl printf vom da perldoc printf. De asemenea, putem recurge la opiunea -f pentru a afla detalii despre o funcie (e.g. perldoc -f connect).
4

Paginile de manual cele mai importante sunt:


perl - o trecere n revist a documentaiilor Perl; perlfaq - rspunsuri la ntrebrile puse frecvent despre Perl (Frequently

Asked Questions - FAQ); sintaxa limbajului (vezi i perlrun - execuia script-urilor Perl, perldebug - depanarea programelor, perlstyle - ghid de stil, perlfunc - funcii predefinite, perlsub - subrutinele Perl);
perlsyn perldata - structurile de date Perl (vezi i perlre - expresii regulate, perldsc - introducere n structuri de date, perllol - liste de liste, perlref - re-

ferine, perlvar - variabile predefinite);


perlop - operatorii i precedena lor; perlmod - modulele Perl (vezi i perlmodlib); perlobj

suport pentru programarea obiectual (vezi i perltool tutorial privind programarea orientat-obiect, perlbot - exemple de obiecte). Pentru a avea acces la una dintre documentaiile dorite, este suficient s tastm, de exemplu, man perlsyn. Versiunile mai vechi de Perl puneau la dispoziie documentaia n format text (Plain Old Documentation - POD). Pentru amnunte, consultai man pod, iar pentru a o converti n alte formate se pot folosi comenzile pod2man, pod2html sau pod2text. De asemenea, cititorii interesai pot parcurge articolele postate pe grupurile de tiri comp.lang.perl sau documentaiile n format hipertext de la http://www.perl.com/perl/. 1.3 Trecere n revist a limbajului Spre deosebire de alte limbaje, Perl este un limbaj interpretat, n sensul c instruciunile Perl nu sunt convertite n cod executabil (nu se genereaz un fiier executabil, spre a fi rulat independent de interpretorul Perl). Vom spune despre programele Perl c sunt script-uri, un limbaj de tip script fiind destinat s prelucreze, s automatizeze i s integreze facilitile oferite de un anumit sistem (e.g., sistem de operare, server Web, navigator Web, aplicaie de birou). Alte limbaje de tip script sunt bash, Python, Tcl/Tk ori JavaScript. Perl nu pune la dispoziie un interpretor clasic, n sensul c un script Perl nu este interpretat linie cu linie, ci n prealabil va fi compilat complet, de o component numit motor (engine) Perl, rezultnd un limbaj intermediar, realizndu-se diverse optimizri i
5

raportndu-se posibililele erori/avertismente sintactice sau semantice. Acest cod intermediar, n cazul n care nu apar erori, va fi dat spre execuie interpretorului Perl.

Modalitatea de execuie a unui script Perl Avnd n vedere c Perl este un interpretor (similar shell-ului bash), prima linie a unui fiier surs Perl va trebui s fie urmtoarea:
#!/usr/bin/perl

Aceast linie indic ncrctorului sistemului de operare locaia interpretorului Perl (sar putea n unele cazuri s difere de directorul /usr/bin, dai whereis perl pentru a vedea unde a fost instalat). Ea va fi ignorat n alte medii diferite de UNIX (Linux), fiind considerat simplu comentariu. Pentru a putea fi executat, fiierul memornd script-ul Perl va trebui s aib permisiunea de execuie setat prin comanda chmod. Un prim program Perl n continuare, vom scrie un program Perl din care vom putea remarca principalele caracteristici definitorii ale limbajului. Ne propunem s concepem un script care s contorizeze numrul de apariii ale elementelor dintr-un document XML:
#!/usr/bin/perl # # # # elemente_xml.pl program care furnizeaza lista elementelor unice prezente intr-un document XML si numarul de aparitii ale fiecaruia

my %elemente, %aparitii; # programul principal while (<>) { # cit timp se mai poate citi de la intrarea standard...

if (/<[^\/>]*>/) { # am intilnit "<", orice alte caractere # exceptind "/>" urmate de ">" # apelam o rutina de extragere a unui element &extragere_element; } } # am terminat de prelucrat # vom afisa lista elementelor gasite &afiseaza_elemente(); # gata! exit; # subrutina de afisare a elementelor gasite # se vor sorta cheile tabloului asociativ %elemente # si se va afisa la iesirea standard fiecare cheie sub afiseaza_elemente { # pentru fiecare element al tabloului... foreach $element (sort keys %elemente) { # afisam formatate numele de element si # numarul aparitiilor lui printf "%-20s - %2d aparitii.\n", "'$elemente{$element}'", $aparitii{$element}; } } # subrutina de extragere a numelor de elemente # apelata de fiecare data cind un element este detectat # intr-o linie citita de la intrarea standard # aceste nume vor fi stocate intr-un tablou asociativ # pentru extragerea numelor de elemente se va folosi # o expresie regulata =~ si variabilele $' si $& sub extragere_element { $restul_liniei = $_; # atita timp cit in linia transmisa mai sunt # alte elemente XML... while ($restul_liniei =~ /<[^\/>]*>/) { $restul_liniei = $'; $element = $&; # orice caracter majuscul e transformat in minuscul $element =~ tr/A-Z/a-z/; # orice "<" sau ">" este eliminat $element =~ s/(<|>)//g; # trecem la urmatoarea iteratie # daca elementul e instructiune de procesare

next if /^(<\?)/; # il introducem in tablou, daca nu exista, # altfel incrementam numarul de aparitii if ($elemente{$element} eq "") { $elemente{$element} = $element; $aparitii{$element} = 1; } else { $aparitii{$element}++; } } # final de "while" } # final de subrutina

Programul anterior se poate edita folosind orice editor de texte (e.g. vi, joe sau emacs). Vom salva codul sub denumirea elemente_xml.pl i vom seta permisiunile de execuie dup cum urmeaz:
(infoiasi)$ chmod 755 elemente_xml.pl

Pentru a invoca interpretorul Perl vom folosi una dintre urmtoarele forme:
(infoiasi)$ perl elemente_xml.pl

sau:
(infoiasi)$ ./elemente_xml

Un exemplu de execuie a acestui script este urmtorul (datele vor fi citite de la intrarea standard; vom semnala terminarea introducerii lor prin CTRL+D, caracterul EOF - End Of File n Linux):
(infoiasi)$ ./element_xml <?xml version="1.0" ?> <studenti> <student> <nume>Gabriel Enea</nume> <an>4</an> </student> <student> <nume>Silvana Solomon</nume> <an>4</an> </student> <student> <nume>Manuel Subredu</nume> <an>3</an> </student> </studenti> ^D

Rezultatul afiat la ieirea standard va fi:


'an' 'nume' 'student' 'studenti' 3 3 3 1 aparitii. aparitii. aparitii. aparitii.

Interpretorul Perl poate fi rulat cu diverse opiuni, de exemplu opiunea -w care va afia toate avertismentele n timpul compilrii i rulrii codului intermediar. De multe ori, aceast opiune va fi utilizat din raiuni de verificare a corectitudinii programului. Desigur, pot fi date i alte opiuni, pentru mai multe detalii cititorul fiind ndemnat s consulte man perl. Aceste opiuni pot fi transmise interpretorului i n cadrul liniei de preambul al codului, de exemplu:
#!/usr/bin/perl -w -t

O opiune util este "-e" care ne permite s executm linii de cod Perl direct din linia de comenzi:
(infoiasi)$ perl -e 'print "Salut!"'

Astfel, putem folosi aceast opiune pentru a afla versiunea curent a limbajului, recurgnd la afiarea valorii variabilei predefinite $]:
(infoiasi)$ perl -e 'print "$]\n";' 5.006

De asemenea, utiliznd opiunea -v putem afla versiunea curent a distribuiei Perl instalate n sistem:
(infoiasi)$ perl -v This is perl, v5.6.0 built for i386-linux

Caracteristici principale Putem observa c programul de mai sus este foarte asemntor cu un program scris n limbajul C sau cu un script bash. n cele ce urmeaz vom ncerca s descriem caracteristicile principale ale limbajului: sintaxa - limbajul Perl are o sintax inspirat din C, delimitatorii fiind spaiile albe. Dup cum era de ateptat, Perl este case sensitive, iar comentariile sunt precedate de caracterul "#". Fiecare instruciune a limbajului este terminat de ";", iar parantezele acolade sunt delimitatori de bloc de instruciuni. Recomandm indentarea construciilor sintactice Perl i utilizarea ct mai multor comentarii pentru ca programele s poat fi uor de parcurs i de neles de ctre cititor.

tipuri de date i variabile - prima linie a programului declar dou tablouri asociative care vor stoca elementele gsite i respectiv numrul de apariii ale acestora:
my %elemente, %aparitii;

Reamintim faptul c o variabil reprezint o zon (de obicei, contigu) de memorie n care se stocheaz o valoare de un anumit tip, zonei fiindu-i asociat un nume (identificator al acelei variabile). Aceast zon poate fi public sau privat, permanent sau temporar pe parcursul execuiei unui program. Numele unei variabile trebuie s nceap cu o liter i poate conine caracterele alfa-numerice i "_". Tipurile de date n Perl sunt fie scalare (simple) sau compuse (complexe). Ca tipuri scalare se pot aminti ntregii cu semn i numerele flotante (dubl precizie). Tot drept tip scalar se consider tipul desemnnd iruri de caractere. Fiind un limbaj interpretat, Perl nu impune declararea variabilelor, ele fiind automat iniializate, n funcie de contextul utilizrii. Implicit, se consider c o variabil numeric este iniializat cu 0, iar un ir de caractere cu valoarea "" (ir vid). irurile de caractere sunt delimitate de apostrofuri sau de ghilimele. Ca i n C, putem folosi aa-numitele caractere escape, ca de exemplu "\n" (linie nou) sau "\t" (caracterul tab). Pentru a avea acces la valoarea unei variabile scalare, vom prefixa numele ei cu caracterul "$" dup cum se poate remarca din exemplul de mai jos:
$nr_studenti++; $pi = 3.14152965; $limbaj = "Perl";

10

n loc de a folosi ghilimele sau apostrofuri, irurile pot fi delimitate de construcii precum:
q/Victor Tarhon-Onu/ # identic cu 'Victor Tarhon-Onu' qq/Victor Tarhon-Onu/ # identic cu "Victor Tarhon-Onu" # executia unei comenzi, identic cu `ls -la` qx/ls -la/ qw/Perl C Java/ # lista de cuvinte

Ca i la shell-ul bash, diferena dintre apostrofuri i ghilimele ca delimitatori de ir este dat de faptul c valoarea variabilelor este accesibil n cazul ghilimelelor:
print "Studenti: $nr_studenti\n"; # variabila $limbaj nu va fi expandata print 'Acest $limbaj este greu?';

Drept tipuri complexe avem la dispoziie: tablourile indexate sunt liste ordonate de scalari, elementele unei liste fiind accesibile prin intermediul unui indice numeric; numele unui vector va fi precedat de caracterul "@", iar indicele va porni de la zero i va fi ncadrat ntre paranteze ptrate:
@absenti[$nr_studenti] = 20; @limbaje = ("Ada", "C", "Java", "Lisp", "Perl"); @mix = ("Pink", 1978, "Floyd", $pi);

Dup cum se poate remarca, un tablou poate conine elemente eterogene, de tipuri scalare diferite. Elementele delimitate de "(" i ")" compun o list. Accesarea unui element se va realiza astfel (caracterul "@" este nlocuit cu "$" pentru c selectm un element scalar):
$limbaje[4]

De asemenea, putem avea acces la un sub-tablou indicnd un interval de indici (sub-tabloul fiind tot un tablou va avea numele prefixat de "@"):
print "Primele trei limbaje: @limbaje[0..2]\n";

Pentru a aduga i elemente la sfritul unui tablou, vom putea uzita de funciile predefinite push() i pop(), respectiv:
push(@limbaje, "Prolog"); print "Ultimul limbaj eliminat:", pop(@limbaje);

Dac dorim s adugm i s tergem elemente la i de la nceputul unui tablou, vom utiliza unshift() i shift(), respectiv.

11

Lungimea unui tablou va putea fi aflat astfel (cele trei construcii au acelai efect):
$nr_limbaje = @limbaje; $nr_limbaje = scalar(@limbaje);

Pentru ca elementele unui tablou s devin cuvinte ale unui ir de caractere, vom utiliza o construcie de genul:
$sir = "@limbaje";

Implicit, elementele tabloului vor fi delimitate de un spaiu. Pentru a schimba delimitatorul, vom apela la variabila scalar predefinit cu numele "@"" dup cum se observ n urmtorul exemplu:
$" = "|"; $sir = "@limbaje"; print $sir, "\n";

Tablourile pot fi utilizate nu doar n partea dreapt a unei atribuiri, ci i n partea stng:
($primul, $al_doilea) = @limbaje; ($primul, @restul) = @limbaje;

Pentru prima linie, variabila $prima va primi valoarea primului element al tabloului @limbaje, iar $al_doilea valoarea celui de-al doilea element al aceluiai tablou. n a doua linie, $prima va primi de asemenea valoarea primului element al tabloului, dar @restul va fi un tablou coninnd restul elementul tabloului @limbaje. Folosind o construcie similar putem realiza atribuiri multiple de variabile scalare ntr-o singur linie de program:
($studenti, $profesori) = ($absenti, 7);

Aceasta are acelai efect ca atribuirile individuale:


$studenti = $absenti; $profesori = 7;

tablourile asociative (hash) sunt tablouri n care indicele numeric este substituit de un ir de caractere. Le putem vedea ca perechi (cheie, valoare), cheile sau valorile nefiind ordonate. Tablourile asociative vor fi accesate precednd numele lor cu caracterul "%", putndu-le iniializa astfel:
# numarul de studenti din fiecare grupa %grupe = ("grupa1", 25, "grupa2", 20,

12

"grupa3", 24, "grupa4", 25);

O modalitate mai intuitiv este:


%grupe = ("grupa1" "grupa2" "grupa3" "grupa4" => => => => 25, 20, 24, 25);

Pentru a accesa un anumit element, vom putea scrie:


print "Grupa a 3-a are $grupe{"grupa3"} studenti.\n";

ntre acolade vor putea fi precizate numai nume de chei, nu valori ale cheilor, iar cheile nu pot fi accesate specificnd valorile lor ntre acolade. O cheie trebuie s fie unic, dar valorile cheilor pot fi duplicate. Conversia din tabel indexat n tabel asociativ i invers se poate realiza tot prin intermediul atribuirii obinuite. Asupra unui tablou asociativ nu mai putea aplica funciile push(), pop(), shift() sau unshift(), dar putem folosi funciile keys() i values() pentru a obine lista cheilor i respectiv cea a valorilor unui tablou asociativ. Aceste liste pot fi iterate cu ajutorul instruciunii foreach. Funcia standard each() returneaz o pereche cheie-valoare putnd fi folosit de asemenea la parcurgerea unui tablou asociativ:
while (($grupa, $studenti) = each(%grupe)) { print "Grupa $grupa are $studenti studenti.\n"; }

Inserarea se poate face simplu prin:


$grupe{"grupa5"} = 20;

Un element se poate elimina cu ajutorul funciei delete(), iar existena unui element se poate afla prin exists():
if exists($grupe{"grupa4"}) { delete($grupe{"grupe4"}); }

Pentru sortarea unui tablou, vom apela funcia sort(). Aceast funcie permite precizarea unei funcii de comparaie a elementelor definit de utilizator. Inversarea unei liste de elemente se va realiza cu reverse().

13

Remarci Din moment ce numele de variabile sunt prefixate de caractere diferite n funcie de tipul variabilelor, putem folosi n acelai program nume de variabile precum %studenti, $studenti i @studenti fr ambiguiti. Pentru a evita conflictul cu nume de variabile sau de funcii predefinite (care ntotdeauna sunt scrise cu minuscule), vom putea alege identificatori de variabile scrii cu majuscule:
# se evita conflictul cu numele de functie log() open(LOG, 'httpd.log');

Sunt puse la dispoziie diverse variabile predefinite, utile n anumite contexte. Se pot meniona, de exemplu, variabilele:
$$ - identificatorul procesului curent; $? - codul de eroare returnat de ultima comand executa-

t;
$0 - numele programului care se execut; $] - versiunea interpretorului Perl, ca numr zecimal (e.g.

5.006);
$@ - mesajul de eroare semnalat de interpretorul Perl re-

turnat n urma execuiei celei mai recente funcii eval();


$, - separatorul de ieire folosit de print() pentru afia-

rea cmpurilor de date;


$\ - separatorul de ieire pentru afiarea nregistrrilor; $" - separatorul utilizat la afiarea listelor; $_ - intrarea implicit sau spaiul de cutare ntr-un ir

(poate fi folosit i $ARG). De asemenea, sunt disponibile urmtoarele tablouri:


@ARGV - argumentele furnizate scriptului ($ARGV[0] refer

primul argument, nu numele programului);


%ENV - variabilele de mediu disponibile; @INC - lista locaiilor bibliotecilor standard Perl, utilizate la

includere.

14

Desigur, putem combina valorile scalare cu tablourile indexate sau asociative, genernd structuri de date deosebit de complexe (tablouri asociative coninnd ca elemente alte tablouri indexate sau asociative, liste de liste etc.). Pentru amnunte, se poate consulta man perllol.

n afara tipurilor prezentate, mai pot fi utilizate referinele la subrutine (funcii sau proceduri), prefixate de caracterul "&" sau la alte obiecte.

Putem crea o referin la orice variabila sau subrutin Perl, prin prefixarea acelui identificator cu caracterul "\":
$referinta_la_mediu = \%ENV; $referinta_la_rutina = \&sortare;

Aceast construcie este similar celei oferite de limbajul C prin intermediul operatorului & (address-of). Dereferenierea se realizeaz cu ajutorul operatorului $. De asemenea, se poate folosi construcia "*" pentru a defini un typeglob. Un typeglob (tip global) poate fi privit la un substitut al tuturor variabilelor care poart acelai nume, iar atunci cnd este evaluat, un typeglob returneaz o valoare scalar care reprezint toate obiectele Perl purtnd numele respectiv (e.g. scalari, tablouri, descriptori de fiier, subrutine). Pentru o variabil, putem preciza scopul (sau domeniul vizibilitii ei). n mod normal, orice variabil folosit undeva ntr-un program va fi accesibil (vizibil) oriunde n cadrul acelui program. Pentru a limita vizibilitatea unei variabile, vom folosi una dintre urmtoarele declaraii:
my declar o variabil ca fiind disponibil doar n cadrul blocului

de instruciuni curent, n interiorul unei subrutine sau n cadrul unui eval(). Pot fi declarate cu my doar variabile scalare sau tablouri (indexate ori asociative).
local este similar cu my, cu excepia faptului c variabila va fi

disponibil dinamic n cadrul unui bloc, subrutine sau eval(). O variabil local va salva valoarea variabilei globale cu acelai nume i o va restaura la prsirea blocului, subrutinei sau construciei eval() n care a fost declarat. Un exemplu de utilizare a declaraiei local:
$numar = 5; print "Inainte: $numar\n";

15

{ local $numar; for ($numar = 2; $numar <= 6; $numar++) { print "Numarul este $numar\n"; } } print "Dupa: $numar\n";

Pentru a testa dac o variabil este definit vom putea utiliza funcia predefinit defined(). O variabil scalar care nu conine nici o valoare valid (numr sau ir de caractere) va fi considerat nedefinit, stocnd valoarea special undef. Cuvntul cheie undef poate fi utilizat pentru a declara ca nedefinite diferite variabile:
undef $absente; undef &calcul_perimetru;

operatorii sunt cei similari din limbajul C (la fel, precedena lor este aceeai). Specifici limbajului Perl sunt urmtorii operatori:
** este operatorul de exponeniere (similar celui din Fortran); ast-

fel, 2 la puterea 5 va fi scris 2**5;


\ este operatorul unar de creare a unei referine; =~ este operatorul de ataare a unei expresii scalare la un ablon

(pattern) al unei expresii regulate;


!~ este similar precedentului operator, dar valoarea returnat este

negat logic; astfel, urmtoarele construcii sunt echivalente:


$sir !~ /sablon/ not $sir =~ /sablon/ x este operatorul de multiplicare a unui ir sau tablou:

# un rind de 80 de caractere "?" @rind = ('?') x 80; # un tablou hash initializat @studenti = qw(Silvana Daniel Gabriel); @note{@studenti} = (10) x @studenti; . este operatorul de concatenare a irurilor de caractere (poate fi

regsit i la PHP):
$salut = "Buna " . "ziua!" . "\n";

16

.. este operatorul de definire a unui interval, putnd fi utilizat n

contextul listelor de numere sau irurilor de caractere:


# afisarea valorilor de la 1 la 33 print (1..33); # toate combinatiile de la 'aa' la 'zz' @combinatii = ('aa'..'zz'); # ultimele 3 limbaje print @limbaje[-3..-1];

Pentru compararea valorilor numerice se vor utiliza operatorii relaionali <, >, <=, >=, == i != (ca n C). Pentru a compara iruri de caractere se vor folosi operatorii lt, gt, le, ge, eq i ne (ca n Fortran). Aceti operatori vor returna 1 pentru valoarea logic "adevrat" i "" (irul vid) pentru valoarea logic "fals". Se mai poate folosi <=> pentru valori numerice care va returna -1 dac operandul stng este mai mic dect cel drept, 0 dac operanzii sunt egali i +1 dac operandul stng este mai mare ca operandul drept. Pentru iruri de caractere, n loc de <=> vom folosi cmp.

17

Observaii Operatorul de autoincrementare ofer o funcionalitate suplimentar putnd incrementa i un ir de caractere:


print ++($grupa = 'g1'); # afiseaza 'g2'

Operatorul unar - poate fi utilizat, de asemenea, pentru iruri, producnd acelai ir, dar prefixat de caracterul "-":
$unu = "unu"; $minus_unu = -"unu";

n Perl, exist o multitudine de operatori unari care la prima vedere par funcii; astfel, sin, cos, log, int, rand, oct, hex, exists, delete, glob, ref, my, return sau exit sunt de fapt operatori unari. Astfel, putem s nu ncadrm argumentele ntre paranteze, cele dou linii fiind echivalente:
$valoare = hex "CB74"; $valoare = hex("CB74");

Utilizarea lui exists ca operator poate fi urmrit n continuare:


print "Grupa exista\n" if exists $grupe{"grupa3"};

Operatorii pe bii pot fi utilizai nu numai pentru ntregi, ci i pentru celelalte tipuri scalare:
# vom obtine "020.44" print "123.45" & "234.56"

Operatorii logici || i && (similari cu cei din C) nu vor returna 0 sau 1, ci ultima valoare evaluat. De asemenea, pot fi folosii, avnd aceeai semantic, operatorii or i and (desigur, n loc de operatorul negaie logic ! poate fi utilizat not).
open(FISIER, "index.html") || die "Fisierul nu poate fi deschis\n";

Perl pune la dispoziie i operatorii de asignare, astfel nct urmtoarele construcii sunt echivalente (unde OP este un operator Perl):
$variabila OP= $valoare; $variabila = $variabila OP $valoare;

18

instruciunile limbajului n Perl sunt n fapt expresii evaluate pentru efectele lor colaterale. O secven de instruciuni formeaz un scop denumit bloc, n general un bloc fiind delimitat de paranteze, fiecare instruciune a blocului terminndu-se cu ";". n afar de instruciuni, un program Perl mai poate cuprinde declaraii care pot fi vzute drept instruciuni dar care sunt efective la momentul compilrii, nu la rulare. Explicit, trebuie declarate obligatoriu numai declaraiile de formate i de subrutine (dup cum vom vedea mai jos).

Ca i n alte limbaje, instruciunile pot fi grupate n instruciunile de asignare, instruciunile de test i instruciuni de control. Pentru instruciunile de test sau cele iterative, trebuie s precizm faptul c pentru obinerea valorilor logice ntotdeauna se va evalua n cadrul unui context scalar. Regulile sunt: Orice ir de caractere este evaluat la valoarea "fals" dac este vid ("") sau conine caracterul zero ("0");

Orice numr este evaluat ca "fals" dac are valoarea 0 (sau 0.0);

Orice referin este adevrat; Orice valoare nedefinit se consider a fi fals.

Majoritatea instruciunilor sunt similare celor din limbajele C sau Java, cu precizarea faptului c att if, ct i for sau while necesit prezena obligatorie a acoladelor. Astfel, urmtoarea linie este corect n C, dar genereaz eroare n Perl:
if ($nr_studenti >= 30) printf ("Prea multi studenti...\n");

n loc de elseif la o instruciune if imbricat se va scrie elsif. O instruciune specific limbajului Perl este unless (complementara lui if) fiind echivalent cu un if avnd condiia de test negat:
unless ($nr_studenti < 30) { print "Prea multi studenti...\n"; }

Mai natural, putem scrie instruciunile if i unless n forma postfixat:


print "Prea multi studenti...\n" if ($nr_studenti >= 30); $nr_studenti-- unless $nr_studenti;

La fel, instruciunea de ciclare while poate fi scris astfel:


$nr_studenti++ while $nr_studenti < 30;

19

Complementara lui while este until, putnd fi folosit n conjuncie cu do:


do { $linie = <STDIN>; # prelucreaza linia... } until $linie eq ".\n";

Alturi de for, avem la dispoziie foreach, utilizat mai ales la iterarea tablourilor, dup cum am vzut. Expresia din parantez este ntotdeauna evaluat ca list, fiecare element al acesteia fiind atribuit pe rnd variabilei de ciclu. Variabila de ciclu este o referin a listei, nu o copie a acesteia. Astfel, modificnd ntr-un ciclu foreach variabila de ciclu vom asista la modificarea tabloului pe care l itereaz:
@note = (9, 9, 7, 10, 5, 8, 8); foreach $nota ( @note ) { print "$nota\n" unless $nota != 10; $nota++; } print "@note\n";

Instruciunile while, for i foreach pot include o instruciune continue (folosit rareori) care va defini un bloc de instruciuni ce va fi executat de fiecare dat cnd s-a terminat blocul precedat de cuvntul cheie while sau la comanda explicit de trecere la urmtoarea iteraie. De exemplu, codul:
for ($grupa = 1; $grupa < 5; $grupa++) { print $grupe{$grupa}; }

este echivalent cu:


$i = 1; while ($grupa < 5) { print $grupe{$grupa}; } continue { $grupa++; }

Dup cum se poate remarca, semantica lui continue n Perl difer de cea a instruciunii continue a limbajului C. Pentru a modifica fluxul firesc de iterare al unui ciclu, se pot folosi next i last. Comanda next (similar instruciunii continue din C ori Java) permite saltul la sfritul blocului de instruciuni i nceperea urmtoarei iteraii. Comanda

20

last (similar cu break din C) va termina complet ciclul asupra cruia se aplic.

Mai poate fi utilizat i redo care restarteaz o iteraie, fr a se evalua din nou condiia (blocul continue, dac exist, nu este executat). Un exemplu (a doua grup nu va fi afiat):
for ($grupa = 1 ; $grupa <=4 ; $grupa++) { next if $grupa == 2; print "Grupa: $grupa\n"; }

subrutinele sunt funcii sau proceduri care pot fi definite de utilizator oriunde n program, pot fi ncrcate dintr-un alt fiier (via do, require ori use) sau se pot genera dinamic, "din zbor", recurgnd la funcia eval().

Declaraia unei subrutine are sintaxa:


sub nume ( parametri ) { bloc }

Lista parametrilor poate lipsi, la fel i blocul de instruciuni:


# definirea unui prototip sub aleatoriu (@);

Rutina aleatoriu va avea un singur argument de tip scalar, putnd fi apelat astfel: aleatoriu(7). Uzual, la momentul declarrii unei subrutine se realizeaz i definirea corpului ei:
sub listeaza_limbaje { print "Limbaje:\n"; foreach $limbaj ( @_ ) { print "\t$limbaj\n"; } }

Apelarea unei subrutine se poate realiza n mai multe moduri. De exemplu:


# fara parametri &listeaza_limbaje; # cu parametru ('&' e optional daca se dau parametrii) listeaza_limbaje(@limbaje); # apelarea prin referinta ('&' poate lipsi) &$listeaza_limbaje(@limbaje);

Caracterul "&" poate lipsi din faa unei subrutine dac aceasta a fost definit n prealabil (ori dac a fost importat dintr-un alt modul).
21

Modelul de pasare a parametrilor de intrare i ieire este simplu: toi parametrii unei subrutine sunt transmii prin intermediul unei liste de scalari, iar eventualele valori multiple returnate sunt disponibile tot ca list de scalari, cu conversii automate de tipuri (dac este cazul). Parametrii pasai oricrei rutine Perl vor fi regsii ca tablou n variabila special $_. Orice operaiune cu tablouri poate avea loc, desigur, i asupra acestei variabile. Acest lucru asigur pasarea unui numr variabil de parametri. Mai mult, pentru a avea acces indexat la parametri specifici, putem folosi indici (e.g. $_[0] pentru primul argument sau $_[2] care l desemneaz pe cel de-al treilea). Un anumit parametru poate fi testat dac este definit cu ajutorul funciei defined(). Putem furniza parametri nedefinii cu ajutorul lui undef:
select (undef, undef, undef, $timp);

Pentru ca o rutin s returneze valori codului apelant, vom folosi return (dac trebuie transmis un tablou, vom utiliza return @_). Fiecare subrutin poate include variabile private declarate cu my. n Perl subrutinele pot fi apelate recursiv, ca i n alte limbaje. Limbajul Perl pune la dispoziia programatorilor o palet larg de funcii predefinite. n cadrul programului prezentat la nceputul acestui sub-capitol, se observ utilizarea funciei predefinite printf pentru a afia formatat diverse date. O alt funcie des folosit este print (aceast ultim funcie nu realizeaz i formatarea fix a datelor).

22

Prelucrarea fiierelor i directoarelor Manipularea fiierelor la nivelul sistemului se realizeaz uzual prin intermediul descriptorilor de fiier. Un descriptor de fiier desemneaz o conexiune de intrare/ieire ntre programul Perl i sistemul de operare. Ca i alte limbaje de programare, Perl pune la dispoziie trei descriptori de fiier care sunt preluai de la procesul printe al interpretorului de comenzi i sunt asociai dispozitivelor de intrare/ieire deja deschise de acesta: STDIN, STDOUT i STDERR. Aceti descriptori de fiiere au aceeai semnificaie ca stdin, stdout i stderr din limbajul C sau descriptorii 0, 1, respectiv 2 din bash. Pentru numele descriptorilor de fiiere limbajul Perl rezerv un spaiu de nume separat: aa cum putem avea o variabil scalar $x, un tablou @x, un tablou asociativ %x, o subrutin x etc., n acelai program putem avea i descriptorul de fiier x, fr nici un pericol de confuzie. Descriptorii STDIN, STDOUT i STDERR pot fi utilizai fr a-i deschide, pentru c ei sunt implicit deschii. Pentru citirea unui ir de caractere de la intrarea standard, folosind STDIN, vom recurge la funcionalitatea oferit de operatorul "<>".
print STDOUT "Un nume, va rugam: "; $nume = <STDIN>; print STDOUT "Salut, $nume.\n";

n acest exemplu remarcm i specificarea explicit a descriptorului STDOUT ca argument al funciei print(). n variabila $nume vor fi stocate caracterele preluate de la intrarea standard, inclusiv caracterul newline care marcheaz finalul introducerii irului de la terminal. Uneori este de dorit ca acest ultim caracter s fie eliminat. Pentru a realiza acest lucru vom apela funcia predefinit chop():
$nume = <STDIN>; chop($nume); print "Salut, $nume.\n";

O alt funcie util este chomp() care va terge toate caracterele newline de la sfritul parametrului primit i va returna numrul de caractere eliminate. Operatorul "<>" poate fi folosit pentru orice descriptor de fiier. n conjuncie cu o variabil scalar va realiza citirea unei linii de fiier. De asemenea, poate fi utilizat ntr-o atribuire a unui tablou, caz n care se va citi ntreg coninutul unui fiier, fiecare element al tabloului reprezentnd o linie a acelui fiier:
@linii = <DESCRIPTOR> 23

La fel, funcia print() poate avea ca prim argument un descriptor de fiier (vezi i exemplele de mai jos). Dac nu se specific nici o variabil, atunci operaiile de intrare/ieire se vor realiza prin intermediul variabilei speciale $_. O alt variabil pe care o putem folosi este $. care va indica numrul curent al liniei dintr-un fiier, numerotarea pornind de la 1. Similar altor limbaje, deschiderea unui fiier se realizeaz cu ajutorul subrutinei open() care accept unul, doi sau trei parametri:
open (DESCRIPTOR) open (DESCRIPTOR, NUMEFIS) open (DESCRIPTOR, MOD, NUMEFIS) DESCRIPTOR este descriptorul asociat numelui de fiier (numele fiierului poate avea

mai multe semnificaii, dup cum vom vedea mai jos), NUMEFIS reprezint numele de fiier cruia i se asociaz descriptorul DESCRIPTOR, iar MOD specific maniera n care va fi deschis fiierul. NUMEFIS nu semnific neaprat numele unui fiier din sistemele de fiiere locale sau montate prin reea. n primul caz variabila $DESCRIPTOR conine numele fiierului, iar dup apelarea lui open $DESCRIPTOR va fi alocat i un descriptor de fiier cu acelai nume.
Mod
<

Descriere

Echivalent C

Citire Citire i scriere Trunchiere i scriere Trunchiere i scriere, cu posibilitatea citirii Scriere, adugare la sfrit

"r" "r+" "w" "w+" "a"

+<

>

+>

>>

Modurile n care pot fi deschise fiierele nchiderea unui fiier se realizeaz cu subrutina predefinit close() care primete ca unic argument descriptorul de fiier dorit a fi nchis. Un exemplu de deschidere, citire i nchidere a unui fiier este urmtorul:
# parcurgem /etc/passwd

24

my $DESCRIPTOR; my $NUMEFIS="/etc/passwd"; open (DESCRIPTOR, "<", $NUMEFIS) || die "Nu se poate deschide $NUMEFIS: $!\n"; my ($username, $passwd, $uid, $gid, $gecos, $home, $shell); while (<DESCRIPTOR>) { ($username, $passwd, $uid, $gid, $gecos, $home, $shell) = split(/:/); print "$username are drepturi de root.\n" if $uid == 0; print "$username este un utilizator privilegiat.\n" if $gid < 90; } close(DESCRIPTOR);

Apelurile echivalente ale funciei open() n acest caz ar putea fi:


open (DESCRIPTOR, "<$NUMEFIS"); open (DESCRIPTOR, $NUMEFIS);

Numele fiierului poate fi precedat sau urmat de caracterul "|", caz n care NUMEFIS poate fi un ir de comenzi externe de la care se va prelua ieirea standard sau care vor avea drept intrare datele de ieire scrise n descriptorul DESCRIPTOR. Urmtoarele apeluri sunt echivalente din punctul de vedere al rezultatului obinut:
open(DESCRIPTOR, "</etc/passwd"); open(DESCRIPTOR, "cat /etc/passwd|"); open(DESCRIPTOR, "-|", "cat /etc/passwd");

Astfel, putem nlnui execuia unor procese prin intermediul mecanismului pipe prezent i la bash. Un exemplu n care datele scrise ntr-un descriptor sunt preluate de un ir de comenzi externe poate fi urmtorul (foarte asemntor de altfel cu precedentul):
my ($INPUT, $OUTPUT); my $infile="/etc/passwd"; open || open || (INPUT, "<", "/etc/passwd") die "Nu se poate deschide /etc/passwd: $!\n"; (OUTPUT, "|-", "sort -u") die "Nu se poate lansa sort: $!\n";

my ($username, $passwd, $uid, $gid, $gecos, $home, $shell); while (<INPUT>) { ($username, $passwd, $uid, $gid, $gecos, $home, $shell) = split(/:/); print OUTPUT "$username are drepturi de root.\n" if $uid == 0; print OUTPUT "$username este un utilizator privilegiat.\n"

25

if $gid < 90; } close(INPUT); close(OUTPUT);

Acelai rezultat se poate obine prin duplicarea descriptorului de fiier corespunztor ieirii standard:
my ($INPUT, $OUTPUT); my $infile="/etc/passwd"; open || open || open || (INPUT, "<","/etc/passwd") die "Nu pot deschide /etc/passwd: $!\n"; (OLDOUT, ">&STDOUT") die "Nu pot duplica STDOUT: $!\n"; (STDOUT,"|-","sort -u") die "Nu pot lansa comanda sort: $!\n";

my ($username, $passwd, $uid, $gid, $gecos, $home, $shell); while (<INPUT>) { ($username, $passwd, $uid, $gid, $gecos, $home, $shell) = split(/:/); print "$username are drepturi de root.\n" if $uid == 0; print "$username este un utilizator privilegiat.\n" if $gid < 90; } close(INPUT); close(STDOUT); open(STDOUT, ">&OLDOUT");

Un alt exemplu, n care vom afia linie cu linie coninutul unui fiier, fiecare linie fiind precedat de numrul ei, este:
while(<>) { print "$. : $_"; }

Operatorul "<>" poate fi utilizat i fr a specifica un descriptor, n acest caz citirea efectundu-se de la intrarea standard. Se pot folosi, de asemenea, funciile uzuale seek(), tell() i flock(), similare celor din limbajul C. Pentru prelucrarea coninutului directoarelor exist un set de funcii diferite de cele destinate operrii cu fiiere. Astfel, opendir(), closedir(), seekdir(), telldir() au corespondeni similari printre funciile pentru lucrul cu fiiere. Funcia rewinddir() poate fi suplinit printr-un apel al lui seekdir().
26

Exemplu de citire a coninutului unui director (simuleaz comanda ls):


my ($DIR, $dirname); die "Avem nevoie de cel putin un argument!\n" unless (defined($dirname = $ARGV[0]) && $dirname ne ""); opendir(DIR,$dirname) || die "Nu putem deschide directorul $dirname: $!\n"; my $file; my $raspuns = "y"; while (defined($raspuns) && $raspuns=~/y|d/i) { rewinddir(DIR); while ($file = readdir(DIR)) { print "$file\n"; } print "Mai afisam inca odata acestui director?"; $raspuns = <STDIN>; } closedir(DIR);

Permisiunile unui fiier pot fi setate folosind funcia chmod care primete aceeai parametri ca apelul de sistem similar din C. Alte funcii predefinite pentru lucrul cu fiiere i directoare sunt mkdir(), chdir(), rename(), rmdir(), chown(), fileno(), ioctl(), lstat(), link(), symlink() i unlink(). Apelul lor n Perl este similar cu cel din limbajul C. Pentru a testa existena sau tipul unui fiier, n limbajul Perl se pot folosi, de asemenea, construcii similare celor din bash. Cteva exemple:
print "Dati un nume de fisier: "; $nume = <STDIN>; chomp $nume; if ( -r $nume && -w $nume ) { print "$nume poate fi citit/scris.\n"; }

O alt facilitate oferit este cea a expandrii coninutului unui director folosind specificatori de fiier. n Perl acest lucru se realizeaz fie cu ajutorul operatorului "<>", fie prin intermediul funciei predefinite glob() i poart numele de globbing.
@pagini = <*.html>; @pagini = glob("*.html");

Dup cum se observ, am folosit meta-caracterul "*" pentru a genera o list cu numele tuturor fiierelor .html din directorul curent.

27

Un alt exemplu, n care tergem toate fiierele stocate n directorul /tmp:


foreach (</tmp/*>) { unlink || warn "Eroare la stergerea $_: $!\n"; }

Semnalarea erorilor i avertismentelor Din cele de mai sus se poate remarca faptul c apelarea unor funcii precum open() se realizeaz n conjuncie cu operatorii or sau || pentru a verifica dac survin erori i a indica natura lor. n cazul unei erori fatale putem apela die() care oprete forat execuia programului, afind mesajul specificat ca argument. Codul de eroare poate fi capturat prin intermediul variabilei speciale $!. Dac mesajul nu este terminat de caracterul "\n", atunci funcia die() va afia i numrul liniei de program care a cauzat eroarea.

O funcie nrudit este warn() care nu va opri execuia programului, ci doar va afia irul primit ca argument, considerndu-l mesaj de avertisment:
open(LOG, ">>httpd.log") || warn "Eroare la deschidere: $!";

28

1.4 Expresii regulate


Pentru a nelege funcionalitatea programului prezentat la nceputul acestei seciuni mai trebuie s ne referim la una dintre cele mai interesante faciliti oferite de limbajul Perl: expresiile regulate (pentru fundamentele teoretice ale expresiilor regulate, cititorul interesat poate parcurge cartea T. Jucan, Limbaje formale i automate, Editura MatrixRom, Bucureti, 1999). n fapt, exist un numr larg de utilitare i aplicaii care ncorporeaz expresiile regulate ca parte a funcionalitii interne a respectivelor programe: comenzile UNIX/Linux de procesare a liniilor (grep, sed sau awk) sau chiar shell-urile din sistem. n afar de Perl, i alte limbaje ofer suport direct pentru expresii regulate, putem da ca exemple Python ori Tcl. O expresie regulat reprezint un ablon (pattern) cruia, pe baza unor reguli precise, i se poate asocia unui text. Pentru lucrul cu expresiile regulate, limbajul Perl pune la dispoziie mai muli operatori care, pe lng rolul de delimitare, ofer un set de opiuni pentru cutare i/sau substituie n cadrul unui text. Variabila implicit n care se realizeaz diferite aciuni implicnd expresii regulate este $_, iar specificarea altei variabile se realizeaz prin intermediul operatorului "=~". De notat faptul c, n primele exemple de utilizare pe care le vom da, se vor folosi drept expresii regulate simple iruri de caractere. Pentru a manipula expresii regulate, ne vom sluji de o serie de operatori descrii n continuare. Operatorul m// Acest operator se folosete pentru a cuta un ablon n cadrul unui text dat. Deoarece de cele mai multe ori nu exist nici un pericol de confuzie, caracterul "m" care preced expresia este opional. Se returneaz valoarea logic "adevrat" n cazul n care cutarea se ncheie cu succes, "fals" n rest (putem aadar s-l folosim n cadrul expresiilor logice).
# atita timp cit se introduce ceva de la tastatura while (<STDIN>) { print "Am gasit subsirul \"Victor\" in $_" if m/Victor/; }

29

Cea mai utilizate opiuni ale acestui operator sunt:


i - cutare case-insensitive (majusculele nu difer de minuscule):

while (<STDIN>) { print "Am gasit tag-ul \"<b>\" sau \"<B>\" in $_" if /<b>/i; } g - caut n ir toate secvenele care se potrivesc ablonului:

my $sir = "a b r a c a d a b r a"; my $num_a = 0; while ($sir =~ /a/g) { $num_a++; } print "Am gasit de $num_a ori caracterul \'a\'.\n"; # va afisa "Am gasit de 5 ori caracterul 'a'." o - evalueaz ablonul doar o singur dat. Folosirea lui n cutri succesi-

ve n acelai ablon are ca efect creterea vitezei de cutare.


while (<STDIN>) { print if /$ARGV[0]/o; } x - permite utilizarea de spaii albe i comentarii n cadrul expresiei regula-

te cu scopul de a face codul mai lizibil:


while (<STDIN>) { print if /^e x\ tins /sx; } # tipareste daca linia incepe # cu 'ex tins'

n acest exemplu spaiul dinaintea caracterului "#" care precede un comentariu va fi ignorat, la fel ca i spaiul dintre "e" i "x", dar nu i spaiul alb precedat de un caracter "\" dintre "x" i "t". Operatorul s/// Operatorul s/ablon/text/ permite cutarea i substituia unui ablon cu un text. Un exemplu:
while (<STDIN>) { s/autmat/Automat/i; print;

30

Va nlocui cuvntul autmat dat la intrarea standard cu Automat i va scrie toate liniile citite la ieirea standard indiferent dac substituia s-a efectuat sau nu. Operatorul qr// Acest operator primete ca parametru un ir de caractere pe care l precompileaz ca expresie regulat. Expresia regulat precompilat poate fi memorat ntr-o variabil i refolosit n construcia altor expresii regulate sau poate fi utilizat direct:
my $expr = qr/(autmat|automt)/i; # exemplu de folosire directa while (<STDIN>) { s/$expr/Automat/; print; } my $expr=qr/(autmat|automt)/i; # exemplu de folosire in alte constructii while (<STDIN>) { s/altceva\ $expr\ nimic/Altceva\ Automat\ ceva/; print; }

Am utilizat construcia escape "\ " pentru ca spaiul s nu fie interpretat. Putem preceda cu backslash orice caracter avnd semnificaie aparte pentru a nu mai fi special procesat. De remarcat faptul c operatorii m//, s/// vor folosi valoarea variabilei $_ pentru cutarea ablonului dac nu este utilizat nici unul dintre operatorii =~ sau !~. Delimitarea expresiei regulate i, dac este cazul, a irului substituitor se poate realiza cu alte caractere speciale dect "/". Astfel, secvena de cod de mai jos este perfect valabil:
my $text = "123 /abc XYZ"; # inlocuim "/abc" cu "AbC" print "$text\n" if $text =~ s!/abc!AbC!;

Expresia se mai putea scrie i s#/abc#AbC# sau s|/abc|AbC| ori s@/abc@AbC@. Un alt exemplu, care va afia coninutul tuturor elementelor <pre> dintr-un document HTML (caracterul "/" nu mai putea fi folosit ca delimitator de expresie regulat):
while (<>) { print if m#<pre>#i .. m#</pre>#i; } 31

n acest exemplu, remarcm i utilizarea operatorului .. care se dovedete extrem de util aici pentru extragerea unui interval de linii fr a se reine explicit aceste informaii. Secvene pentru identificarea unui caracter. Multiplicatori Cel mai simplu mod de a identifica un anumit caracter n cadrul unui text este cel de a cuta exact acel caracter. Scrierea unui caracter "a" ntr-o expresie regulat presupune existena aceluiai caracter n irul cruia i se aplica. De multe ori ns am dori s folosim diverse meta-caractere pentru a identifica un set de caractere. Meta-caracterele sunt acele caractere din codul ASCII care nu se identific pe ele nsele n cadrul unei expresii regulate sau chiar al unei secvene de cod-surs (scris n C/C++, Perl etc). n cadrul unei expresii regulate meta-caracterele sunt folosite pentru alctuirea unor construcii cu rol de a identifica diferite secvene de caractere dintr-un text. Urmtoarele caractere ASCII sunt considerate meta-caractere n cadrul unei expresii regulate: Caracterul "." este utilizat n cadrul unei expresii regulate s identifice orice caracter, exceptnd caracterul newline "\n".

Construcia "[...]" reprezint o clas de caractere. De exemplu expresia regulat /[a-z]/ se poate asocia oricrui ir de caractere care conine cel puin o liter minuscul. Bineneles, se pot concepe construcii mai complexe, cum ar fi /[a-z][ATX][0-7]\-[^1-378]/ care va identifica orice text coninnd o succesiune de caractere format, n ordine, de o liter minuscul, una dintre majusculele "A", "T" sau "X", o cifr ntre 0 i 7, semnul minus "-" i oricare cifr diferit de 1, 2, 3, 7 sau 8. De exemplu, comparaia dintre irul %0bX7-0F comparat cu expresia regulat de mai sus se va finaliza cu succes datorit subirului bX7-0.

Meta-caracterul "^" are dou roluri: Folosit n cadrul unei secvene de caractere are rolul de negare. Astfel, [^2-5] va identifica oricare cifr aparinnd mulimii {1, 6, 7, 8, 9, 0}, iar [^a-m] va identifica oricare caracter cu excepia minusculelor de la "a" la "m".

Desemneaz nceputul unei linii, fiind un caracter de poziionare n rest. De exemplu, ^[2-5] va identifica orice ir care ncepe cu o cifr cuprins ntre 2 i 5.

Precedat de un "\" va desemna caracterul "^".

32

Simbolul "$" folosit ntr-o expresie regulat identific sfritul unei linii.

Caracterele "(" i ")" au rolul de a grupa atomi n cadrul expresiei regulate i de a memora valoarea subirurilor din text corespunztoare acestor atomi, fr ns a modifica valoarea expresiei regulate (aceast construcie se mai numete i operator de memorare). Un caracter lipsit de semnificaie sau un metacaracter de poziionare (e.g. "^" sau "$") se numete atom al unei expresii regulate. Putem grupa atomi pentru a forma fragmente ale unei expresii regulate mai complexe.

Fie script-ul:
my ($LOG, $i); open(LOG, ">>/tmp/word_switch.log") || die "Nu pot deschide fisierul: $!\n"; while (<STDIN>) { $i++; s/^(\S+)\s+(\S+)/$2 $1/; print; print LOG "linia $i: s-a inversat \"$1\" cu \"$2\"\n"; } close(LOG);

Acest program va prelua linii de text de la intrarea standard i va afia la ieirea standard inversnd primele dou cuvinte ntre ele, scriind ntr-un fiier modificrile efectuate. Caracterul "|" va da posibilitatea de a alterna ntre dou sau mai multe forme posibile ale unei secvene dintr-un text.
while (<STDIN>) { print if (/[0-9]|[A-Z][a-z]/); }

Urmtorul script va putea identifica orice ir care conine un subir format sau dintr-o liter minuscul urmat de cel puin o cifr, sau dintr-o cifr succedat de cel puin o majuscul. Subirul care se potrivete ablonului va fi tiprit:
while(<>) { print "\"$1\" se potriveste sablonului\n" if (/([a-z]\d+|\d[A-Z]+)/); }

Meta-caracterele "?", "*, "+, "{" i "}" au rolul de multiplicatori ai unui

atom.

33

Un atom al unei expresii regulate urmat de "?" poate identifica de zero sau maxim o singur dat un atom;

Simbolul "*" poate identifica zero, una sau mai multe apariii consecutive ale aceluiai atom;

Un atom urmat de "+" poate s identifice mcar o apariie a ato-

mului. Un exemplu:
while (<STDIN>) { print "Cel putin o aparitie a cuvintului \'web\' la inceputul liniei\n" if (/^(web)+/); }

Multiplicatorul "{}" are o sintax ceva mai complex dect "*" i "+", astfel:
atom{m, n} va identifica ntr-o expresie cel puin m atomi, dar nu

mai muli de n;
atom{m,} va identifica m sau mai muli atomi; atom{,n} va identifica n atomi cel mult; atom{n} va identifica exact n atomi.

Putem face aici observaia c {1,} este echivalent cu "+", {0,1} cu "?", iar construcia {0,} este echivalent cu "*". Valorile lui m i n sunt n intervalul [0, 65535]. Dac meta-caracterul "?" urmeaz unui multiplicator, acesta din urm va avea un caracter ponderat (minimal). Limbajul Perl pune la dispoziie un set de construcii predefinite pentru identificarea unor clase de caractere, dup cum se poate remarca din tabelul urmtor.

34

Construcie

Echivalent

Construcie Echivalentul construciei complementar complementare


\D

\d

(o cifr)
\w

[0-9]

(orice exceptnd cifre)


\W (un caracter

[^0-9]

(un caracter alfanumeric)


\s

[0-9_a-zA-Z]

ne-alfanumeric)
\S

[^0-9_a-zA-Z]

(un spaiu alb)

[\t\r\n\ \f ]

(orice exceptnd spaii albe)

[^\t\n\r\ \f]

Identificarea claselor de caractere Expresia regulat /(.*\d+[A-Z]{3,7})/ poate identifica orice ir de caractere cu urmtoarea componen: ncepe cu oricare caracter(e), continu cu cel puin o cifr i se termin cu cel puin trei majuscule, dar nu mai mult de apte. Totui un ir de forma abc123ABCDEFGHIJKL se va potrivi acestei expresii regulate, condiiile impuse fiind satisfcute, n variabila $1 (s-a folosit () - operatorul de memorare) fiind stocat irul 123ABCDEFG. Dac ns la sfritul acestei expresii mai adugm o constrngere (final de linie, de exemplu, sau alt caracter) multiplicatorul {} va fi forat s se opreasc. Construcia /(\d+[A-Z]{3,7})\;/ va fora ca n componena irului s nu existe mai mult de apte majuscule, nici mai puin de trei, i, mai mult, s fie urmate de caracterul ";". Toi aceti multiplicatori prezentai mai sus vor identifica att de muli atomi ct este posibil. Astfel, [A-Z]{3,7} n prima variant a exemplului prezentat dup ce va gsi n text trei majuscule, va continua cutarea i se va opri la apte dac este posibil. De asemenea, \d+ a identificat toate cele trei cifre din text, dei o posibil variant a valorii lui $1 ar fi fost 23ABCDEFG. n cazul prezenei n expresia regulat a doi (sau mai muli) multiplicatori, cel mai din stnga va identifica mai multe caractere n detrimentul celorlali aflai mai n dreapta. Considerm o variant puin modificat a expresiei de mai sus i anume /^.*(\d+[AZ]{3,7})/. Forma textului pe care l va identifica nu se schimb, ns textul memorat n $1 difer n situaiile n care vor exista mai mult de dou cifre. Folosind n continuare irul abc123ABCDEFGHIJKL, valoarea stocat de $1 va fi 3ABCDEFG.

35

Exist situaii cnd un asemenea comportament al multiplicatorilor nu ne convine. S considerm expresia regulat /(a.*bc)/ i textul dd a ddd bc dddd bc bdd. O comparaie ntre acest ir i /(a.*bc)/ va avea ca rezultat memorarea n $1 a valorii a ddd bc dddd bc. Se observ c dei compararea s-ar fi putut opri dup prima pereche bc, a continuat. n acest caz compararea s-a fcut pn la sfritul irului de caractere, dar nefiind ndeplinite condiiile de identificare s-a revenit la ultima succesiune de caractere "potrivit". Ali identificatori de caractere Limbajul Perl mai pune la dispoziie, alturi de construciile predefinite pentru identificarea unor clase de caractere, i construcii conforme cu standardul POSIX, de forma [:clasa_de_caractere:], utilizate i de funciile PHP. Clasele de caractere (care pot fi utilizate ca mai sus) sunt: alpha, alnum, ascii, cntrl, digit, graph, lower, print, punct, space, upper, word i xdigit. Caracterele incluse n aceste clase de caractere sunt cele pentru care funciile C cu numele isclasa_de_caractere() returneaz "adevrat". Astfel, [[:alnum:]] este echivalent cu [0-9a-zA-Z], [[:word:]] este echivalent cu [0-9a-zA-Z_], [[:digit:]] cu [0-9] etc. De asemenea, limbajul Perl definete construcii cu lungime nul (zero-width assertions) care identific doar contexte, nu caractere, n urmtorul mod:
\b identific limitele unui cuvnt; \B identific orice alt context dect limitele unui cuvnt (interiorul unui

cuvnt);
\A desemneaz nceputul unui ir; \Z identific sfritul unui ir sau naintea caracterului newline de la finalul

irului;
\z identific sfritul unui ir; \G va identifica locul unde are loc ultima potrivire a ablonului n text, n

cazul folosirii opiunii /g a operatorilor m// sau s///. De exemplu "/text\b/" poate identifica " text", "text", "context", dar nu i "textul".

36

Utilizarea variabilelor n expresiile regulate Operatorii delimitatori care ncadreaz expresiile regulate au un comportament asemntor ghilimelelor (double quote). Astfel, ca i n alte cazuri, variabilele care intr n componena unui ablon sunt evaluate la fiecare evaluare a acestuia n vederea cutrii n text. Excepie fac expresiile regulate delimitate de ghilimele simple (single quotes) care inhib evaluarea sau n cazul folosirii opiunii /o care ne asigura de faptul c acea expresie regulat este compilat doar o singur dat. Foarte util n unele cazuri ale utilizrii variabilelor n cadrul expresiei regulate se dovedete operatorul qr//. Un exemplu de folosire al lui qr// n acest caz este evaluarea unor pri ale unei expresii regulate numai o singur dat, artificiu care poate mri viteza de procesare a unor texte folosind expresii regulate complexe avnd pri care rmn neschimbate mai mult timp:
my ($text_de_inlocuit, $text_inlocuit, $expresie); print "Ce text vom inlocui in text? "; chomp($text_inlocuit = <>); print "Cu ce text vom inlocui \"$text_inlocuit\"? "; chomp($text_de_inlocuit = <>); $expresie = qr/$text_inlocuit/; while (<>) { s/$expresie/$text_de_inlocuit/i; print; }

37

Funcii predefinite folosind expresii regulate n conjuncie cu expresiile regulate se pot utiliza urmtoarele funcii predefinite:
tr/// realizeaz translatarea caracter cu caracter a unui text i

are forma:
tr/caractere_de_cutare/caractere_de_nlocuire/

Aceast funcie mai poart numele i de funcie de transliterare. irul de intrare este parcurs caracter cu caracter, nlocuindu-se fiecare apariie a unui caracter de cutare cu corespondentul lui din mulimea caracterelor de nlocuire. Se pot folosi opiunile:
c - va realiza translatarea utiliznd complementara mulimii de ca-

ractere de cutare;
d - va terge toate caracterele din mulimea caracterelor de cutare

care nu au corespondent n setul caracterelor de nlocuire;


s - va reduce secvenele de caractere care au fost nlocuite

folosindu-se acelai caracter la o apariie unic a caracterului respectiv. Cteva exemple:


# majusculele devin minuscule tr/A-Z/a-z/ # http: devine ftp: tr/http:/ftp:/ # caracterele diferite de alfanumerice devin spatii tr/A-Za-z0-9/ /cs split() mparte un ir de caractere n funcie de o expresie regulat i

returneaz un tablou coninnd subirurile care nu satisfac acea expresie regulat. Dup cum vom vedea n seciunea 2.1, funcia va fi foarte folositoare pentru realizarea de script-uri CGI. Pentru a afia numele de cont i directorul home al utilizatorilor din sistem vom putea scrie urmtorul script (folosim fiierul /etc/passwd).
open (FIS, "/etc/passwd") || die "Eroare la deschiderea fisierului\n"; while (<FIS>) { $linie = $_; chomp($linie);

38

@date = split(':', $linie); ($cont, $dir) = @date[0, 6]; print "Directorul home al lui $cont este $dir\n"; } close (FIS);

Elementele returnate de split() se pot memora i n variabile scalare separate. Astfel, pentru a stoca data sistem vom putea scrie urmtoarele linii de cod:
$data_sistem = localtime(time); ($ziua, $luna, $num, $timp, $an) = split(/\s+/, $data_sistem); join() este complementar funciei mai sus amintite, n sensul

c reunete mai multe iruri de caractere n unul singur, delimitate de un scalar. Un exemplu:
$perl = "Perl"; $cpp = "C++"; $java = "Java"; $tcl = "Tcl"; print "Limbaje: ", join(" ", $perl, $cpp, $java, $tcl), "\n"; print "Limbaje: ", join(", ", $perl, $cpp, $java, $tcl), "\n";

O variant alternativ este cea care recurge la utilizarea operatorului de concatenare ".", fr posibilitatea de a specifica elementul de legtur.
eval() poate fi folosit pentru evaluarea/execuia unei expresii Perl.

Contextul execuiei expresiei Perl este contextul curent al programului. Putem considera expresia ca o subrutin sau bloc de instruciuni n care toate variabilele locale au timpul de via egal cu cel al subrutinei ori blocului. Dac nu se specific o expresie ca argument al funciei, se va utiliza n mod firesc variabila special $_. Valoarea returnat de eval() reprezint valoarea ultimei expresii evaluate, fiind permis i folosirea operatorului return. Posibilele erori vor cauza returnarea unei valori nedefinite i setarea variabilei $@ cu un mesaj de eroare. Astfel, eval() unui ablon: poate fi de ajutor n verificarea corectitudinii

sub este_sablonul_valid { my $sablon = shift; return eval { "" =~ /$sablon/; 1 } || 0; }

39

Putem prentmpina afiarea unui mesaj de eroare la apariia excepiei de mprire la zero a unui numr astfel:
print "Impartire la zero" unless eval { $rezultat = $nr1 / $nr2 };

40

1.5 Modulele Perl


Conceptul de pachet Modulele (pachetele) Perl reprezint uniti de cod precompilat, ncapsulnd diferite funcionaliti oferite programatorilor. Un pachet Perl poate fi considerat drept implementarea unei clase pe care o putem instania n cadrul unui script. Subrutinele incluse ntr-un pachet pot juca, de asemenea, rolul de metode, existnd posibilitatea definirii de constructori i destructori. Mai mult, se ofer suport pentru derivarea unei metode aparinnd unui pachet, astfel nct pachetele Perl pot fi ierarhizate. Mai multe pachete pot fi grupate n biblioteci. Vom referi variabilele din alte pachete prefixnd identificatorul variabilei respective cu numele pachetului urmat de "::", dup cum se poate observa din urmtorul exemplu:
$intrare = $main::STDIN;

La fel, pentru metode:


$imagine = new GD::Image(174, 333);

Dac nu este specificat numele pachetului, se consider implicit pachetul main. Astfel, construcia $::var este echivalent cu $main::var. Dac dorim s accesm metode sau date-membru definite ntr-un pachet derivat din altul vom specifica numele ambelor pachete:
$Pachet::Subpachet::variabila

Conceptul de modul Un modul reprezint un pachet public definit ntr-un fiier .pm cu scopul de a fi reutilizat ulterior. Modulele Perl vor fi incluse n program, spre a fi folosite, prin construcia:
use Modul;

La fel, use Modul (); este echivalent cu require Modul;, dar se recomand utilizarea lui use n favoarea unui require. Pentru mai multe detalii, cititorul poate consulta paginile de manual pentru perlmod i perlxs. Sunt puse la dispoziie mai multe module standard (disponibile n orice distribuie Perl actual), dintre care se pot meniona:

41

Carp (pentru controlul erorilor i avertismentelor); Config (pentru acces la opiunile de configurare); CGI (pentru generarea facil de script-uri CGI); Env (pentru accesarea variabilelor de mediu); ExtUtils::Embed (pentru includerea de cod Perl n programele C); File::Find (pentru traversarea recursiv a unui arbore de directoare); File::Handle (pentru manipularea fiierelor folosind descriptori de fiier); File::Path (pentru operaii cu directoare); Math::Complex (pentru prelucrarea numerelor complexe); POSIX (pentru asigurarea interfeei cu standardul POSIX IEEE 1003.1); Search::Dict (pentru cutarea unei chei ntr-un fiier dicionar); Socket (pentru realizarea de operaiuni cu socket-uri); Time::Local (pentru acces la timpul local).

Pentru a gsi toate modulele instalate n sistem (inclusiv cele care nu au documentaii sau au fost instalate n afara distribuiei standard) putem folosi urmtoarea linie de comenzi:
find `perl -e 'print "@INC"'` -name "*.pm" -print

n mod normal, fiecare modul posed propria lui documentaie, accesibil prin intermediul comenzii man din UNIX. Se poate utiliza i comanda perldoc. CPAN Succesul limbajului Perl rezid, n principal, din posibilitatea de a extinde limbajul cu noi funcionaliti oferite de module. n afara modulelor din distribuiile Perl standard, exist o colecie global a tuturor materialelor publice referitoare la Perl, colecie referit sub denumirea CPAN (Comprehensive Perl Archive Network). CPAN ofer un numr impresionant de module grupate pe urmtoarele categorii:
extensii de limbaj i unelte de documentare; suport pentru dezvoltare de programe/module; interfee (la nivel sczut sau ridicat) cu sistemul de operare; comunicarea

ntre

procese,

reea

controlul

dispozitivelor

(e.g., modemuri);
42

tipuri de date i conversii; interfee cu bazele de date; interfee cu utilizatorul; interfee cu alte limbaje de programare; procesarea fiierelor i sistemelor de fiiere; procesarea caracterelor; procesarea fiierelor de configuraie i a parametrilor n linia de comand; suport pentru diverse limbi i alfabete (internaionalizare); autentificare, securitate i criptare; suport pentru pota electronic i grupurile de tiri; suport pentru Web (HTML, HTTP, CGI, XML etc.); utilitare pentru daemoni; suport pentru arhivarea i compresia datelor; procesarea informaiilor grafice; controlul fluxului (excepii, erori etc.); procesarea fluxurilor de date i a fiierelor; altele.

Pentru un listing al tuturor locaiilor Internet referitoare la CPAN, consultai http://www.perl.com/perl/. Instalarea unui modul n unele cazuri va trebui s lum un modul de la CPAN pentru a-l instala i folosi ulterior n cadrul script-urilor noastre. Pentru a fi instalat pe un sistem UNIX/Linux, un modul Perl se regsete fie ca fiier tar arhivat cu gzip (deci are extensia .tar.gz sau .tgz), fie ca fiier .pm (deja dezarhivat). Orice modul n sistem. Perl necesit pentru instalare existena interpretorului Perl

Dup dezarhivare (cu tar -xzf numearhiva.tgz), n directorul n care a fost stocat modulul dorit a fi instalat se dau urmtoarele comenzi (pentru a se putea executa ultima linie, utilizatorul trebuie s aib drepturi de root):

43

perl Makefile.PL make make test make install

Dac se dorete instalarea unui modul ntr-o alt locaie (de exemplu, n directorul privat al unui utilizator), atunci se substituie prima linie cu:
perl Makefile.PL INSTALLDIRS=site INSTALLSITELIB=/home/user/director

Pentru a folosi acel modul n programele noastre, va trebui s prefam fiecare script cu liniile de mai jos:
use lib '/home/user/director' use Modul;

n care /home/user/director este directorul unde a fost instalat modulul denumit Modul. n mod uzual, fiecare modul este acompaniat i de documentaia necesar exploatrii lui. Pentru a avea acces la ea, se folosete utilitarul perldoc:
(infoiasi)$ perldoc XML::Parser

Pentru convertirea documentaiei n format text sau HTML se pot utiliza comenzile pos2text i, respectiv, pod2html, ca n exemplul urmtor:
(infoiasi)$ pod2text Parser.pm >Parser.txt (infoiasi)$ pod2html Parser.pm >Parser.html

1.6 Exemple simple


Vom furniza n continuare o serie de exemple de rutine Perl folositoare. Pentru a verifica validitatea unei adrese de e-mail putem recurge la funcia urmtoare:

sub valid_email { $testmail = shift; return 0 if ($testmail =~/ /); if ($testmail =~ /(@.*@)|(\.\.)|(@\.)|(\.@)|(^\.)/ || $testmail !~ /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/) { return 0; } else { return 1; } }

44

Afiarea, linie cu linie, a coninutului unui fiier se poate realiza astfel, prin intermediul subrutinei urmtoare:

sub gen_file_content() { $file = shift; return 1 unless open(FIL, "<$file"); while(<FIL>) { print; } close (FIL); return 0; }

Determinarea timpului curent i preluarea lui ntr-un ir de caractere formatat corespunztor (pentru Web) se pot realiza via funcia de mai jos:

sub get_time() { my @time = @_; my @MONTHS = ('Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sep', 'Oct', 'Nov','Dec'); my @WDAYS = ('Dum', 'Lun', 'Mar', 'Mier', 'Joi', 'Vin', 'S&icirc;m'); my $sec, $min, $hour, $day, $month, $year; my ($sec, $min, $hour, $day, $month, $year, $wday) = @time; local ($ftime) = $WDAYS[$wday] . "&nbsp;$day&nbsp;" . $MONTHS[$month] . "&nbsp;" . (1900 + $year) . "&nbsp;" . sprintf("%02d", $hour) . ":" . sprintf("%02d", $min) . ":" . sprintf ("%02d", $sec); return ($ftime); }

45

2. Script-uri CGI n Perl


2.1 Primele script-uri CGI
Standard de facto pentru interaciunea clienilor Web cu serverele Web, Common Gateway Interface se afl n prezent la versiunea 1.1. Un program CGI, denumit n mod uzual script, se execut pe serverul WWW, fie n mod explicit (apelat din cadrul paginii printr-o directiv special), fie la preluarea informaiilor aflate n cadrul cmpurilor unui formular interactiv sau coordonatelor unei zone senzitive (image map). CGI confer interactivitate paginilor Web, documentele HTML putnd astfel s-i modifice n mod dinamic coninutul i s permit prelucrri sofisticate de date. Programele CGI pot oferi suport de asemenea la autentificarea utilizatorilor pe partea server. Regulile care trebuie respectate la conceperea unui script CGI sunt urmtoarele: programul scrie datele (marcaje HTML, XML, imagini etc.) spre a fi trimise navigatorului Web la ieirea standard (stdout);

programul genereaz antete care permit serverului Web s interpreteze corect ieirea script-ului (folosindu-se specificaiile protocolului HTTP).

Cele mai multe script-uri CGI sunt concepute pentru a procesa datele introduse n formulare. Un formular se definete n XHTML folosindu-se marcatori specifici pentru afiarea coninutului i introducerea datelor de ctre client, iar script-ul, invocat i executat de serverul Web, va prelua coninutul acelui formular i-l va prelucra, returnnd, eventual, rezultatele ctre navigator. Antetul trimis serverului de ctre programul CGI va respecta specificaiile MIME, coninnd de exemplu Content-type: text/html (document HTML sau XHTML) sau Content-type: image/jpeg (imagine JPEG) ori Content-type: text/plain (text obinuit). Programului CGI i se vor transmite n diverse variabile de mediu sau de la intrarea standard informaii referitoare la datele de procesat sau privitoare la clientul care a iniiat cererea, n funcie de metoda de transfer utilizat. Pentru a fi efective, programele CGI trebuie apelate (implicit sau explicit) din cadrul paginilor Web. Uzual, un script CGI va fi invocat din cadrul unui formular HTML la apsarea butonului de trimitere a datelor ctre server (butonul de tip submit). S presupunem c avem urmtorul exemplu n care un utilizator introduce prin intermediul unui formular dou numere ntregi, iar programul CGI va genera o pagin Web coninnd maximul dintre ele.

46

Formularul XHTML ar putea fi:


<form action="http://www.infoiasi.ro/cgi-bin/max.cgi" method="GET"> <p>V rugm, introducei dou numere:</p> <input name="nr1" size="3" /> <input name="nr2" size="3" /> <br /> <input type="submit" value="Afl maximul" /> </form>

De exemplu, introducnd numerele 7 i 4 i acionnd butonul etichetat "Afl maximul", vom primi o pagin Web (un document marcat n XHTML) care va afia textul "Maximul dintre 7 i 4 este numrul 7" (vezi figura). Presupunnd c n cele dou cmpuri ale formularului (purtnd numele nr1 i respectiv nr2) am introdus valorile 7 i 4 respectiv i am apsat butonul de tip submit (etichetat cu "Afl maximul"), navigatorul va trimite, prin intermediul protocolului HTTP, o cerere ctre serverul Web aflat la adresa dat de URL-ul http://www.infoiasi.ro (adresa este preluat din valoarea atributului action al elementului <form>; script-ul poate fi localizat desigur i prin intermediul unui URL relativ). Desigur, n loc de o adres absolut, putea fi specificat o cale relativ, nsemnnd faptul c se folosete serverul pe care se gsete pagina coninnd formularul. Atunci cnd se trimite cererea HTTP, navigatorul construiete un URL avnd ca sufix informaii despre datele introduse n cmpurile formularului, n cazul nostru http://www.infoiasi.ro/cgi-bin/max.cgi?nr1=7&nr2=4 folosindu-se o codificare special. Pentru fiecare cmp al formularului, se va genera o pereche nume_de_cmp=valoare delimitat de caracterul "&", iar caracterele speciale (ca de exemplu slash-ul sau apostroful) vor fi nlocuite de codul lor numeric, n hexazecimal, precedat de caracterul procent ("%"). Spaiile vor fi substituite de semnul plus ("+"). De exemplu, pentru a trimite textul Cina de la Maxim's se va folosi codificarea Cina+de+la+Maxim%27s.

47

Introducerea datelor n formular i obinerea rezultatului furnizat de script-ul CGI dup acionarea butonului de tip submit Serverul spre care cererea a fost expediat (n cazul sitului www.infoiasi.ro un server Apache rulnd pe un sistem Linux) va procesa datele recepionate conform regulilor proprii. Tipic, configuraia serverului definete unde sunt stocate n cadrul sistemului de fiiere directoarele i fiierele CGI. Fiierele de configurare a serverului n mod uzual se regsesc n directorul /etc/httpd/conf/. De cele mai multe ori, daemonul HTTP (adic serverul Web, regsit ca proces de fundal sub numele httpd) ruleaz pe main sub auspicii de utilizator fictiv (din raiuni de securitate ca nobody sau apache, n mod uzual), fiierele sale fiind stocate (n cazul unui sistem UNIX/Linux) de obicei n directorul /var/www/. Aici, alturi de directorul html ori public_html unde se memoreaz documentele (HTML, CSS, fiiere multimedia, fiiere JavaScript etc.) unui sit Web, se afl i directorul cgi-bin unde ar trebui s fie stocate toate fiierele (script-urile) CGI apelate din cadrul paginilor Web. Aadar URI-ul http://www.infoiasi.ro/cgi-bin/max.cgi va nsemna pentru serverul Web aflat la adresa www.infoiasi.ro urmtoarea aciune: "invoc programul max.cgi aflat la /home/httpd/cgi-bin". Astfel, n loc s trimit ctre navigatorul Web care a iniiat cererea HTTP un document HTML sau un fiier de alt tip, serverul va invoca script-ul CGI specificat (n acest caz max.cgi) i-i va pasa datele furnizate de sufix, de dup semnul ntrebrii (adic irul nr1=7&nr2=4).

48

Aciunea de invocare va avea o semantic diferit n funcie de script-ul CGI conceput. Pentru un script Perl, serverul va invoca un interpretor Perl (n cazul Apache, un modul special mod_perl; de fapt, pentru a permite execuia de programe CGI, serverul Apache se va folosi de serviciile modulului mod_cgi).

Procesul de invocare a unui script CGI Extensia de fiier .cgi nu are nici o relevan n general, dar pot exista diverse reguli de numire a fiierelor CGI executabile dependente de server sau de sistemul de operare pe care ruleaz. Pentru ca un script CGI s poat fi invocat trebuie s poat fi citit i executat de utilizatorul fictiv sub care i desfoar activitatea serverul Web. n funcie de metoda de transfer folosit, script-ul CGI va primi n mod diferit irul de interogare. Pentru metoda GET (metoda implicit de transfer a datelor de la un navigator Web), informaiile din irul de interogare (cele de dup delimitatorul "?") vor fi disponibile ntr-o variabil de mediu purtnd numele QUERY_STRING. Astfel, n cazul exemplului de mai sus valoarea acestei variabile va fi nr1=7&nr2=4).

Metoda POST este util n situaiile n care avem de trimis script-ului CGI spre prelucrare un volum mai mare de date (de exemplu, coninutul unei scrisori ori al unui fiier) sau informaii confideniale (e.g. parole) care nu trebuie s apar n componena URI-ului transmis serverului Web.

Pentru formularele utiliznd metoda POST, datele pasate script-ului vor putea fi accesate de la intrarea standard (stdin), iar lungimea, n octei, a informaiilor trimise va fi disponibil n variabila de mediu CONTENT_LENGTH. De multe ori este util ca ntr-un script CGI s detectm metoda de transfer pentru a prelua datele n mod corespunztor. Pentru aceasta va trebui s se testeze valoarea variabilei de mediu REQUEST_METHOD.
49

Dup cum am vzut mai sus, nainte de a trimite spre navigator pagini Web sau alte tipuri de informaii (multimedia, arhive, documente XML etc.), orice script CGI trebuie s afieze la ieirea standard cmpul HTTP Content-type. Desigur, nici script-urile CGI concepute n Perl nu fac excepie. Astfel, cel mai simplu script este urmtorul:
#!/usr/bin/perl # trimitem antetul HTTP print "Content-type: text/html\n\n"; # trimitem codul HTML, # (folosim facilitatea "here") print <<HTML; <html> <head> <title>Salut!</title> </head> <body bgcolor="white" text="blue"> <p>Salut!</p> </body> </html> HTML

Ca orice alt script CGI conceput n alt limbaj, un script CGI scris n Perl va avea acces la variabilele de mediu furnizate de serverul Web. Acest lucru se poate rezolva prin accesarea tabloului asociativ ENV:
#!/usr/bin/perl # trimitem antetul HTTP print "Content-type: text/plain\n\n"; print "Variabilele de mediu disponibile:\n"; foreach $variabila (sort keys %ENV) { print "$variabila: $ENV{$variabila}\n"; }

50

Preluarea datelor prin metoda GET Pentru a accesa datele transmise prin intermediul metodei GET va trebui s le prelum ca URI codificat din variabila de mediu QUERY_STRING. Ne propunem s scriem un script Perl simplu care preia dintr-un formular valorile a dou numere ntregi i returneaz clientului Web maximul dintre cele numere. Vom scrie aadar urmtorul formular XHTML:
<form action="max.pl.cgi" method="GET"> <p>Introduceti dou numere: <input type="text" name="nr1" size="3" /> <input type="text" name="nr2" size="3" /> <br /> <input type="submit" value="Afl maximul" /> </form>

De exemplu, introducnd numerele 3 i 1 i acionnd butonul "Afl maximul", vom primi o pagin Web care va afia textul "Maximul dintre 3 i 33 este: 33". Script-ul Perl va prelua din variabila de mediu QUERY_STRING irul de interogare codificat:
$interogare = $ENV{'QUERY_STRING'};

Va trebui s divizm acest ir de caractere n perechi (nume de cmp, valoare) i apoi s prelum valorile fiecrui cmp al formularului. Acest lucru se realizeaz n maniera urmtoare, implementnd funcia analiza_parametri() care va returna un tablou asociativ avnd drept chei numele cmpurilor i ca valori valorile acestor cmpuri:
sub analiza_parametri { # variabile locale local($interogare) = @_; # preluam perechi 'camp=valoare' local(@perechi) = split('&', $interogare); local($parametru, $valoare, %parametri); foreach (@perechi) { # preluam valoarea si numele de camp ($parametru, $valoare) = split('='); # decodificam valorile $parametru = &unescape($parametru); $value = &unescape($value);

51

# memoram in tabloul 'parametri' if ($parametri{$parametru}) { $parametri{$parametru} .= "$;$valoare"; } else { $parametri{$parametru} = $valoare; } } return %parametri; }

Mai rmne s decodificm irurile de caractere ("+" va deveni spaiu, iar "%" urmat de dou cifre n baza 16 va fi substituit de caracterul ASCII corespunztor):
sub unescape { local($sir) = @_; # "+" devine spatiu $sir =~ tr/+/ /; # %HH devine caracter ASCII $sir =~ s/%([0-9A-Fa-f]{2})/pack("c", hex($1))/ge; return $sir; }

Script-ul complet max.pl.cgi este urmtorul:


#!/usr/bin/perl -w # calculeaza maximul a doua numere # (se utilizeaza metoda GET) print <<HTML; Content-type: text/html <html><head><title>Maxim</title></head> <body> <h2>Maximul a doua numere</h2> <hr> HTML ; # preluam sirul de interogare # din variabile de mediu QUERY_STRING $interogare = $ENV{'QUERY_STRING'} || die "Sir de interogare vid!\n"; %parametri = &analiza_parametri($interogare); # preluam valorile parametrilor $nr1 = $parametri{'nr1'}; $nr2 = $parametri{'nr2'}; if ($nr1 > $nr2) { $max = $nr1; }

52

else { $max = $nr2; } print "<p>Maximul dintre $nr1 si $nr2 este: $max</p>\n"; print <<HTML; <hr> </body> </html> HTML ; # am terminat exit; sub analiza_parametri { # variabile locale local($interogare) = @_; # preluam perechi 'camp=valoare' local(@perechi) = split('&', $interogare); local($parametru, $valoare, %parametri); foreach (@perechi) { # preluam valoarea si numele de camp ($parametru, $valoare) = split('='); # decodificam valorile $parametru = &unescape($parametru); $value = &unescape($value); # memoram in tabloul 'parametri' if ($parametri{$parametru}) { $parametri{$parametru} .= "$;$valoare"; } else { $parametri{$parametru} = $valoare; } } return %parametri; } # functie de decodificare sub unescape { local($sir) = @_; # "+" devine spatiu $sir =~ tr/+/ /; # %HH devine caracter ASCII $sir =~ s/%([0-9A-Fa-f]{2})/pack("c", hex($1))/ge; return $sir; }

53

Preluarea datelor prin metoda POST Trimind valorile cmpurilor formularului prin metoda POST, nu vom mai consulta variabila de mediu QUERY_STRING, ci vom citi de la intrarea standard CONTENT_LENGTH octei care, desigur, vor trebui decodificai. Pentru decodificare vom folosi rutinele prezentate mai sus, codul script-ului fiind (rutinele analiza_parametri() i unescape() au fost omise):
#!/usr/bin/perl -w # calculeaza maximul a doua numere # (se utilizeaza metoda POST) print <<HTML; Content-type: text/html <html><head><title>Maxim</title></head> <body> <h2>Maximul a doua numere</h2> <hr> HTML ; # preluam sirul de interogare de la # intrarea standard read(STDIN, $interogare, $ENV{'CONTENT_LENGTH'}); die "Sir de interogare vid!\n" unless $interogare; %parametri = &analiza_parametri($interogare); # preluam valorile parametrilor $nr1 = $parametri{'nr1'}; $nr2 = $parametri{'nr2'}; if ($nr1 > $nr2) { $max = $nr1; } else { $max = $nr2; } print "<p>Maximul dintre $nr1 si $nr2 este: $max</p>\n"; print <<HTML; <hr> </body> </html> HTML 54

; # am terminat exit;

55

2.2 Modulul CGI


Pentru realizarea comod de script-uri CGI n Perl, este pus la dispoziie modulul CGI, utilizat n special pentru generarea i procesarea formularelor i a cookie-urilor. Acest modul ofer un obiect generic CGI pentru acces la variabile de mediu, pentru procesarea lor i stocarea rezultatelor. Modulul CGI poate fi utilizat pentru preluarea datelor transmise att prin metoda GET, ct i prin metoda POST, fr a concepe programe separate pentru fiecare metod n parte. Un alt avantaj este dat de posibilitatea de a depana script-urile CGI rulndu-le direct de la prompt-ul Linux, n loc de a fi invocat prin intermediul serverului Web. Modaliti de utilizare Putem folosi modulul CGI prin intermediul a dou paradigme de programare: funcional (procedural) i obiectual. Cele dou paradigme nu difer dect prin modul de acces la funcionalitile modulului: via funcii n primul caz i via metode n al doilea. Urmtorul exemplu folosete paradigma procedural:
#!/usr/bin/perl # utilizam modulul CGI in forma standard use CGI qw/:standard/; # trimitem antetul HTTP print header(); # afisam antetul paginii Web print start_html(-title => "Un salut"); # afisam diferite elemente HTML print h1('Salut!'), p('Un paragraf...'); # afisam finalul de document print end_html();

Acelai script, din perspectiva orientat-obiect, este:


#!/usr/bin/perl # utilizam modulul CGI use CGI; # instantiem obiectul CGI $c = new CGI;

56

# trimitem antetul HTTP print $c->header(); # afisam antetul paginii Web print $c->start_html(-title => "Un salut"); # afisam diferite elemente HTML print $c->h1('Salut!'), $c->p('Un paragraf...'); # afisam finalul de document print $c->end_html();

Preluarea parametrilor Cele mai uzuale utilizri ale modulului CGI sunt cele n care sunt implicate formularele Web ale cror valori de cmpuri trebuie prelucrate comod. Pentru a prelua toi parametrii pasai script-ului ne putem sluji de un tablou, apelnd metoda param():
@parametri = $c->param;

Dac dorim s prelum valoarea unui anumit parametru vom folosi una dintre construciile:
@prieteni = $c->param('prieteni'); $culoare = $c->param('culoare');

n prima variant, rezultatul este preluat de un tablou, deoarece cmpul prieteni poate conine elemente multiple ale unui marcator <select>. Varianta procedural este:
$o_culoare = param('culoare');

Atunci cnd dorim s asignm o nou valoare unui parametru, vom scrie, de exemplu:
$c->param(-name=>'culoare', -value=>'rosu');

Procesarea antetului HTTP Aa cum am vzut, nainte de a genera cod-surs HTML, un script CGI trebuie s trimit obligatoriu antetul HTTP. Acest lucru se realizeaz prin intermediul metodei sau funciei header():
# trimite Content-type: image/gif print $c->header('image/gif');

Metoda header() poate fi folosit i pentru a seta alte cmpuri HTTP:

57

print $c->header( # Content-type -type => 'image/png', # codul de stare HTTP -status => '402 Payment Required', # timpul de expirare -expires => '+3d', # parametru-utilizator -Cost => '$ 0.01');

Pentru atributul -expires pot fi specificate valori de timp precum now (acum), +30s (dup 30 de secunde), +15m (dup 15 minute), +5h (dup 5 ore) sau +3M (dup 3 luni). Sunt acceptate i valori negative. Pot fi, de asemenea, trimise cmpuri definite de utilizatori, n exemplul de mai sus Cost. Acest lucru permite folosirea unor protocoale noi, fr a trebui s actualizm modulul CGI. Mai mult, se poate folosi metoda redirect() pentru a redirecta navigatorul ctre alt locaie:
# redirectare in functie de limba if ($limba eq 'ro') print $c->redirect('/ro/index.html'); else print $c->redirect('/en/index.html');

De asemenea, se pot invoca diverse metode care s ofere valorile variabilelor de mediu specifice HTTP. Astfel, putem apela metode precum:
query_string returneaz irul de interogare CGI; remote_addr()

furnizeaz

adresa

IP

calculatorului

client

care

invocat script-ul;
remote_host() ca mai sus, dar se returneaz numele simbolic al calculatorului

client;
request_method()

furnizeaz

metoda

HTTP

utilizat

(GET,

POST

sau HEAD);
user_agent() identific numele i versiunea agentului-utilizator (navigatorului,

de cele mai multe ori) folosit pe calculatorul client. Iat un exemplu n care redirectm automat browserul, n funcie de sistemul de operare al clientului:
#!/usr/bin/perl

58

use CGI; $url = 'http://www.infoiasi.ro'; for (CGI::user_agent()) { # simularea unui 'switch' $pag = /Linux/ && 'linux.html' || /HP-UX/ && 'hpux.html' || /SunOS/ && 'sunos.html' || /Mac/ && 'macos.html' || /Win|MSIE/ && 'win.html' || /.*/ && 'generic.html'; } print "Location: $url/$pag\n\n";

n loc de user_agent() puteam folosi $ENV{HTTP_USER_AGENT}, desigur. Alte funcii utile oferite de modulul CGI sunt:
escape() convertete un ir de caractere n codificarea utilizat de URI-

urile CGI;
unescape()

convertete un ir codificat CGI n reprezentarea

sa normal;
use CGI qw/escape unescape/; $sir = escape('~/:#?'); print unescape($sir); escapeHTML() convertete un ir de caractere, substituind orice caracter

HTML ilegal prin entitatea corespunztoare;


unescapeHTML() convertete un ir de caractere coninnd entiti

HTML n ir obinuit.
use CGI qw/escapeHTML unescapeHTML/; $sir = escapeHTML('Un sir mai <mic>...'); print unescapeHTML($sir);

59

Modulele CGI n fapt, modulul CGI este suplinit i de urmtoarele module:


Base.pm ofer funcionalitile de baz pentru dezvoltarea de script-uri

CGI;
BasePlus.pm extinde modulul precedent, adugnd faciliti precum

upload de fiiere;
Request.pm este responsabil cu analiza i procesarea cererilor HTTP; Form.pm este folosit pentru a genera mai uor formulare Web, n loc de a

scrie cod HTML;


MiniSvr.pm implementeaz un server HTTP minimal; Response.pm este utilizat pentru a genera antete HTTP; Carp.pm permite redirectarea mesajelor de eroare ctre navigator, spre un

fiier jurnal sau un fiier utilizator.

De menionat aici i faptul c serverul Apache incorporeaz direct interpretorul Perl prin intermediul modulului mod_perl, astfel nct timpul de execuie a script-urilor CGI concepute n Perl s fie minim. Pentru fiecare script Perl invocat, serverul Web va lansa o nou instan a interpretorului implementat de mod_perl. De asemenea, la iniializarea serverului (pornirea daemonului httpd) putem configura mod_perl astfel nct s se ncarce modulele Perl dorite n acest moment i nu la prima lor utilizare, accelerndu-se timpul de execuie a script-urilor.

60

2.3 Exemple de script-uri


Furnizm n continuare o serie de exemple de script-uri CGI, folosind sau nu modulul CGI. Calendar ncepem cu un exemplu clasic al unui script care afieaz calendarul unui an (furnizat de utilizator sau anul curent). Pentru generarea calendarului se va recurge la comanda UNIX cal. Acest script nu folosete modulul CGI i poate fi invocat indiferent de metoda HTTP utilizat (pentru aceasta vom testa valoarea variabilei de mediu REQUEST_METHOD).
#!/usr/bin/perl -w # afiseaza calendarul, # folosind comanda UNIX 'cal' # (scriptul va fi functional indiferent # de metoda HTTP folosita: GET sau POST) $CAL = '/usr/bin/cal'; @ani = (1990..2033); %interogare = &furnizeaza_interogarea; # preluam anul if ($interogare{'an'}) { $an = $interogare{'an'}; } else { chop($an = `date +%Y`); } # antetul paginii print <<HTML; Content-type: text/html <html><head><title>Calendar</title></head> <body text="blue" bgcolor="white"> <h3 align="center">Calendarul pentru anul $an </h3> HTML ; # cream formularul din care se va prelua anul dorit print "<form method=\"POST\">\n"; print "Selectati anul: <select name=\"an\">\n"; # va fi selectat implicit anul curent foreach $un_an (@ani) { 61

print "<option"; # selectam implicit anul curent if ($un_an == $an) { print " selected"; } print ">$un_an</option>\n"; } print "</select>\n"; # butonul de trimitere print '<p><input type="submit" value="Afiseaza calendarul">'; print "</form>\n<hr>\n"; # ne pregatim de afisarea calendarului # verificam anul unless ($an=~/^\d{4}$/) { print "<p style='color:red'>Anul trebuie sa aiba 4 cifre</p>\n"; exit 0; } # executam comanda 'cal' pasindu-i ca parametru anul dorit chop($calendarul = `$CAL $an`); # rezultatul returnat de 'cal' # este afisat preformatat cu <pre> print <<HTML; <pre> $calendarul </pre> <hr> </body> </html> HTML ; # am terminat exit; # rutinele de procesare a interogarii sub furnizeaza_interogarea { local($interogarea); # preluam metoda cererii local($metoda) = $ENV{'REQUEST_METHOD'}; # daca e GET, preluam datele din variabila de mediu if ($metoda eq 'GET') { $interogarea = $ENV{'QUERY_STRING'}; # dace e POST, preluam de la intrarea standard } elsif ($metoda eq 'POST') { read(STDIN, $interogarea, $ENV{'CONTENT_LENGTH'}); }

62

# iesim, daca nu e furnizata nici o data return () unless $interogarea; # procesam interogarea return &analiza_parametri($interogarea); } sub analiza_parametri { # variabile locale local($interogare) = @_; # preluam perechi 'camp=valoare' local(@perechi) = split('&', $interogare); local($parametru, $valoare, %parametri); foreach (@perechi) { # preluam valoarea si numele de camp ($parametru, $valoare) = split('='); # decodificam valorile $parametru = &unescape($parametru); $value = &unescape($value); # memoram in tabloul 'parametri' if ($parametri{$parametru}) { $parametri{$parametru} .= "$;$valoare"; } else { $parametri{$parametru} = $valoare; } } return %parametri; } # functie de decodificare sub unescape { local($sir) = @_; # "+" devine spatiu $sir =~ tr/+/ /; # %HH devine caracter ASCII $sir =~ s/%([0-9A-Fa-f]{2})/pack("c", hex($1))/ge; return $sir; }

Numrarea liniilor unui fiier Acest exemplu ilustreaz aciunea de upload, prin preluarea de pe calculatorul client a unui fiier n vederea numrrii liniilor, cuvintelor sau caracterelor coninutului su. Pentru aceasta, vom genera un formular HTML utiliznd capabilitile puse la dispoziie de modulul CGI. Sursa acestui script Perl, denumit numara.pl.cgi este urmtoarea:
63

#!/usr/bin/perl use CGI; # instantiem obiectul CGI $cerere = new CGI; print $cerere->header; &interogare($cerere); &numara($cerere); print $cerere->end_html; # am terminat exit; # afiseaza formularul de interogare a utilizatorului sub interogare { my($cerere) = @_; # definim tipurile de calcule pe care le oferim my(@tipuri) = ('numara linii', 'numara cuvinte', 'numara caractere'); print <<END; <h3>Numara</h3> <p>Selectati <b>Browse</b> pentru a alege un fisier text, apoi apasati butonul <b>Numara</b>. END ; # genereaza un formular print # formular eteroge $cerere->start_multipart_form, "Introduceti numele fisierului:", $cerere->filefield(-name => 'fisier', -size => 30), "<br>", $cerere->checkbox_group(-name=>'numarare', -values=>\@tipuri, -defaults=>\@tipuri), "<p>", # afiseaza butoanele standard # de tip 'reset' si 'submit' $cerere->reset, $cerere->submit(-label=>'Numara'), $cerere->end_form; }

64

# numara linii, cuvinte, caractere sub numara { my($cerere) = @_; # procesam datele introduse if ($fisier = $cerere->param('fisier')) { print "<hr>\n"; print "<h3>Fisier: <tt>$fisier</tt></h3>\n"; # procesam continutul fisierului while (<$fisier>) { $linii++; $cuv += @cuv = split(/\s+/); $caract += length($_); } # vedem ce tip de numarare a fost selectat grep($num{$_}++, $cerere->param('numarare')); if (%num) { print "<b>Linii:</b> $linii<br>\n" if $num{'numara linii'}; print "<b>Cuvinte:</b> $cuv<br>\n" if $num{'numara cuvinte'}; print "<b>Caractere:</b> $caract<br>\n" if $num{'numara caractere'}; } else { print "<b>Nu ati selectat nici " . "o metoda de numarare.</b>\n"; } } # sfirsit de if }

Afiarea unei imagini aleatoare Ne propunem s scriem un script care la fiecare rulare s afieze o alt imagine preluat aleatoriu dintr-un director cu fiiere grafice n formatele JPEG (Joint Picture Experts Group), GIF (Graphical Interchange Format) sau PNG (Portable Network Graphics). Codul surs al acestui script simplu este:
#!/usr/bin/perl # afiseaza continutul unui fisier grafic ales aleatoriu use CGI qw/:standard/; # constante folosite pentru specificarea # directoarelor care contin imagini $DIR_RADACINA = '.'; $DIR_IMAGINI = 'img';

65

chdir "$DIR_RADACINA/$DIR_IMAGINI" or die "directorul de imagini e inaccesibil."; # preluam intr-un tablou fisierele JPEG, GIF si PNG @imagini = <*.{jpg,gif,png}>; # alegem imaginea $imagine = $imagini[rand(@imagini)]; die "eroare la selectarea imaginii" unless $imagine; # redirectam navigatorul spre imaginea aleasa print redirect("$DIR_IMAGINI/$imagine");

Memorarea preferinelor utilizatorilor n cadrul acestui script vom putea observa capabilitile oferite de modulul CGI n ceea ce privete manipularea cookie-urilor. Utilizatorul va putea s introduc prin intermediul unui formular interactiv numele su, culoarea de fundal a paginii i mrimea fontului implicit. Aceste preferine vor fi stocate n cookie-uri pe maina client a utilizatorului pn la urmtoarea vizit sau maxim 30 de zile. La invocarea script-ului se verific dac preferinele exist i se modific nfiarea paginii n concordan cu acestea.
#!/usr/bin/perl use CGI; # constante utilizate in cadrul formularului # culori de fundal dorite @culori=qw/gray coral bisque beige gold green lime linen orchid seashell sienna silver wheat/; # dimensiunea fontului @marime=("<implicit>", 1..7); # instantiem obiectul CGI $c = new CGI; # preluam vechile preferinte din cookie-ul "preferinte" %preferinte = $c->cookie('preferinte'); # preluam noile preferinte ale utilizatorului prin # inspectarea valorilor transmise prin formular $preferinte{'culoare'} = $c->param('culoare') if $c->param('culoare'); $preferinte{'nume'} = $c->param('nume') if $c->param('nume'); $preferinte{'marime'} = $c->param('marime') if $c->param('marime'); # alegem culoarea implicita 'silver' daca nu exista $preferinte{'culoare'} = 'silver' unless $preferinte{'culoare'};

66

# modificam parametrii cookie-ului astfel incit # sa fie persistent si sa reflecte noile preferinte $un_cookie = $c->cookie(-name=>'preferinte', -value=>\%preferinte, -expires=>'+30d'); # trimitem cookie-ul print $c->header(-cookie=>$un_cookie); # generam titlul paginii, incluzind numele utilizatorului $title = $preferinte{'nume'} ? "Pagina lui $preferinte{nume}!" : "Pagina utilizatorului"; # vom crea pagina HTML, oferind posibilitatea # de a schimba preferintele de # culoare, nume de utilizator si marimea fontului print $c->start_html(-title=>$title, -bgcolor=>$preferinte{'culoare'}); # stabilim marimea fontului print "<basefont size=$preferinte{marime}>\n" if $preferinte{'marime'} > 0; print <<END; <h3 align="center">$title</h3> <hr> <p align="justify"> Modificati modul de aparitie al paginii completind formularul de mai jos. Preferintele dumneavoastra vor fi valabile timp de maxim 30 de zile.</p> END ; # vom crea formularul de preferinte print join("\n", "<hr>", $c->start_form, "Prenumele d-voastra: ", $c->textfield(-name=>'nume', -default=>$preferinte{'nume'}, -size=>30), "<br>", "Culoarea de fundal preferata: ", $c->popup_menu(-name=>'culoare', -values=>\@culori, -default=>$preferinte{'culoare'}), "Marimea fontului: ", $c->popup_menu(-name=>'marime', -values=>\@marime, -default=>$preferinte{'marime'}),

67

"<br>", $c->submit(-label=>'Memoreaza preferintele'), "<hr>");

Alte exemple, relativ mai complexe, sunt disponibile n volumele: S. Buraga et al., Programare Web n bash i Perl, Polirom, Iai, 2002:
http://www.infoiasi.ro/~cgi/

S. Buraga (coord.), Situri Web la cheie. Soluii profesioniste de implementare, Polirom, Iai, 2004: http://www.infoiasi.ro/~busaco/books/webapps/

68

3. Teme propuse
1. S se conceap n limbajul Perl un script CGI care s fie utilizat pentru evaluarea expresiilor matematice cu paranteze. Se vor realiza mai multe variante, cu i fr ajutorul modulului CGI. 2. S se scrie un script CGI care s afieze un citat celebru ales aleatoriu dintr-o list, n funcie de localizarea geografic a vizitatorilor (de exemplu, pentru un vizitator din Romnia se va afia un citat n limba romn). 3. S se realizeze o aplicaie Web implementat n Perl care s proceseze informaiile privitoare la cursele aeriene furnizate de o anumit companie. 4. Prin intermediul unor script-uri Perl, s se simuleze o agend de birou, permind realizarea de adnotri pe zile, sptmni, luni, includerea de legturi Web, programarea de ntlniri etc. Agenda va include un mini-editor de texte, un calculator, un calendar i un ceas electronic. Se vor prevedea autentificarea i salvarea preferinelor utilizatorilor. 5. S se proiecteze i implementeze un sit Web pentru alegerea de ctre prini a numelor de copii. Utilizatorii vor putea formula cerine pentru nume, n funcie de sex, numr de silabe, litera de nceput etc. Se vor genera i statistici referitoare la cele mai cutate nume. 6. S se realizeze un sit Web pentru vizualizarea i trimiterea de ilustrate electronice, pe diverse teme (peisaje, orae celebre, figuri de personaliti, opere de art etc.). 7. S se conceap o aplicaie Web pentru vizualizarea diferitelor informaii (utilizare, capacitate, imagine interioar, dotare etc.) despre ncperile care compun cldirile unei anumite organizaii, incluznd punerea la dispoziia utilizatorului de hri, planuri de situaie i avnd posibiliti de cutare. 8. S se implementeze o aplicaie WWW care furnizeaz diverse statici privind accesul la documentele de pe un sit, folosind datele coninute de fiierul access_log generat de serverul Web. Statisticile vor cuprinde grafice cu zonele de unde au fost fcute cereri, orele de acces maxim, paginile accesate cel mai des etc.

69

Resurse bibliografice
(n ordinea relevanei)

1. S. Buraga et al., Programare Web n bash i Perl, Polirom, Iai, 2002: http://www.infoiasi.ro/~cgi/ 2. . Truan-Matu et al., Prelucrarea documentelor folosind XML i Perl, Matrix Rom, Bucureti, 2001 3. S. Buraga (coord.), Situri Web la cheie. Soluii profesionale de implementare, Polirom, Iai, 2004: http://www.infoiasi.ro/~busaco/books/webapps/ 4. S. Buraga, Proiectarea siturilor Web (ediia a II-a), Polirom, Iai, 2005: http://www.infoiasi.ro/~design/ 5. D. Acostchioaie, S. Buraga, Utilizare Linux, Polirom, Iai, 2004: http://www.infoiasi.ro/~linux/ 6. D. Acostchioaie, Administrarea sistemelor Linux (ediia a III-a), Polirom, Iai, 2005: http://www.adt.ro/admin/ 7. 8. 9. * * *, Perl: http://www.perl.com/ * * *, Introduction to CGI: http://hoohoo.ncsa.uiuc.edu/cgi/intro.html * * *, CGI Resources: http://www.cgi-resources.com/

10. * * *, Consoriul Web: http://www.w3.org/

70

S-ar putea să vă placă și