Introdução

Este texto foi organizado em duas partes. Na primeira, descrevemos a sintaxe da linguagem Perl e abordamos suas principais funções pré-definidas. Na segunda parte, explicamos o padrão CGI e mostramos alguns exemplos de programas CGI escritos em Perl. Assumimos que o leitor é experiente em alguma linguagem de programação, tem familiaridade com o sistema operacional UNIX e conhece os marcadores da hypertext markup language (HTML).




1. Perl (Practical Extraction and Report Language)

Apresentamos a seguir uma breve descrição da linguagem Perl, na versão 5.000. Para o leitor interessado em aprofundar-se na linguagem, recomendamos o livro Programming Perl, escrito por Larry Wall, Tom Christiansen e Randal L. Schwartz, editado pela O'Reilly and Associates. Para o leitor interessado em um texto mais básico, recomendamos o livro Learning Perl, escrito por Randal L. Schwartz e também editado pela O'Reilly and Associates.

Recomendamos ainda uma visita ao site www.perl.com onde o leitor poderá encontrar uma grande quantidade de informação sobre Perl, tais como livros, revistas, tutoriais, bibliotecas de funções, etc.



1.1 Características da linguagem Perl

Perl é uma linguagem de programação de uso geral, desenvolvida por Larry Wall na década de 80, baseada principalmente na linguagem C e na linguagem awk. Uma das principais características de Perl é facilitar a manipulação de textos e processos. Além disso, Perl possui um alto grau de portabilidade, modularidade e reusabilidade de código. Perl é uma linguagem interpretada, o que torna a carga de um programa escrito em Perl um pouco mais lenta que a carga de programas escritos em algumas linguagens compiladas. Por outro lado, isto permite uma maior flexibilidade na sintaxe da linguagem, como veremos adiante.

Perl suporta orientação a objetos, no entanto neste texto omitiremos esta parte da linguagem. Um dos objetivos principais da linguagem é ajudar o programador a aumentar sua produtividade escrevendo programas pequenos, no entanto complexos e poderosos. Existem versões gratuitas do Perl para diversas plataformas como Unix, Windows, MVS, VMS, Macintosh, OS/2, Amiga, etc. Por estas e outras características, Perl é uma das linguagens preferidas para a preparação de programas CGI.

Assim como C, Perl é uma linguagem case-sensitive. As sentenças (linhas) do programa devem terminar com um ; (ponto-e-vírgula), a menos que ela termine com um bloco ou que seja a última sentença dentro de um bloco (por exemplo, if ($idade < 21) { print "menor" }). Os blocos devem estar dentro de { } (chaves). O conteúdo de uma linha após um # é entendido como comentário. Uma peculiaridade de Perl é que toda sentença é também uma expressão, dessa forma, a seguinte linha está sintaticamente correta:

if ((print "Olá") && $a > 5) { $a = 10; }



1.2 Literais

Listamos a seguir exemplos de literais em Perl.

Numéricos: 12 , -5 , 1_234 (equivale a 1234) , 3.1415 , 5E-10 (equivale a 5x10-10), 0xff (hexadecimal), 0377 (octal, indicado pelo 0 a esquerda)

Perl representa números com até 15 casas decimais e com valor absoluto entre 10-324 e 10308

String: 'abc' , q/abc/ , qq/abc/ (ou praticamente qualquer outro par de delimitadores ao invés de /.../) , "abc"

Estas quatro formas representam o mesmo literal string abc. Usando as duas últimas formas (qq/.../ ou "...") é feita interpolação e as sequências de escape são processadas. Interpolar uma string é substituir as variáveis contidas na string por seus respectivos valores. Dessa forma, se o valor da variável $temp é 36, o literal "temperatura: $temp" resulta em temperatura: 36.

As sequências de escape são:

\t
tabulação
\n
quebra de linha
\r
retorno de carro
\f
quebra de página
\b
backspace
\a
alarme (bip do alto-falante)
\e
esc
\c
control
\l
torna minúsculo o caractere seguinte
\u
torna maiúsculo o caractere seguinte
\L
torna minúsculos os caracteres seguintes até encontrar um \E
\U
torna maiúsculos os caracteres seguintes até encontrar um \E
\033
caractere equivalente ao código 033 (octal) na tabela ASCII
\x8b
caractere equivalente ao código 8b (hexadecimal) na tabela ASCII

Obs: qx/COMANDO/ representa a string retornada pela execução do COMANDO. Por exemplo: qx/date/ retorna a data corrente. Uma forma alternativa é colocar o COMANDO dentro de `` (acento grave).

Vetores: (1, "casa", 8) , ( ) (vetor vazio) , (1..4) (equivale a (1, 2, 3, 4)) , ('az'..'bc') (equivale a ('az', 'ba', 'bb', 'bc')) , qw/casa bola dado/ (equivale a ('casa', 'bola', 'dado'))

Hashes (vetores associativos): (nome => luis, sexo => M), (nome , luis, sexo , M) (estas duas formas são equivalentes)



1.3 Variáveis

Em Perl, não há necessidade de declarar variáveis. No entanto, para evitar conflito com variáveis globais, é possivel declarar uma variável, visível no escopo local da seguinte forma:

my VARIÁVEL;

Na primeira vez que uma variável é referenciada, ela é criada dinamicamente e seu valor é inicializado como sendo nulo. O identificador (nome) de uma variável pode ser constituído de letras, dígitos (0 a 9) e _ (underscore), sendo o primeiro caractere uma letra ou _, e pode ter até 252 caracteres. Estas regras também se aplicam para os demais identificadores em Perl (identificadores de funções, de rótulos, etc). Mais adiante listaremos alguns identificadores de variáveis que já possuem significado especial em Perl.

Perl não é uma linguagem tipada, dessa forma, as variáveis não possuem tipos. O valor das variáveis pode ser visto como número ou como string, dependendo do contexto. Por exemplo, se as variáveis $a e $b valem 5 e 3 respectivamente, a expressão $a + $b naturalmente resulta em 8. No entanto, se avaliarmos estas variáveis no contexto de string, como na expressão $a.$b, onde . é o operador de concatenação, o resultado será a string 53. Um valor nulo vale 0, no contexto numérico, e vale uma string vazia, no contexto de string. No contexto lógico, um zero,u uma string vazia, um lista vazia ou um hash vazio valem falso, qualquer outra coisa vale verdadeiro.

Existem 3 estruturas de dados primitivas em Perl:

Variáveis escalares: contêm um único valor. Seu identificador deve ser precedido de $. Por exemplo: $nome, $nota1.

Vetores (listas): contêm uma lista de valores heterogêneos. Seu identificador deve ser precedido de @. Por exemplo: @nomes, @notas. Para referenciar um único elemento do vetor devemos indicar entre [ ] (colchetes) o índice do elemento, referenciando o vetor no contexto escalar, ou seja, usando $ ao invés de @. Por exemplo: $nomes[0] (em Perl, os vetores são indexados a partir de 0), $notas[3]. Se notas é um vetor, $notas retorna o número de elementos do vetor, $notas[-1] retorna o valor do último elemento do vetor e $#notas retorna o índice do último elemento do vetor. É possível fazer referência a uma parte do vetor: @nomes[2, 4, 1], @notas[3..8]. Um elemento de um vetor pode ser também um vetor, dessa forma, $notas[3][5] referencia o sexto elemento do quarto elemento do vetor notas. Podemos assim criar vetores multidimensionais.

Hashes (vetores associativos): contêm uma lista de valores heterogêneos com uma chave associada a cada valor. Seu identificador deve ser precedido de %. Por exemplo: %nomes, %notas. Para referenciar um único elemento do hash devemos indicar entre { } (chaves) a chave associada ao elemento, referenciando o hash no contexto escalar, ou seja, usando $ ao invés de %. Por exemplo: $nomes{32}, $notas{rui}. Podemos referenciar uma parte de um hash: @notas{rui, ana} (será retornada uma lista contendo os valores associados às chaves rui e ana). Se notas é um hash, $notas retorna verdadeiro, se o hash não estiver vazio, ou falso, caso contrário.



1.4 Operadores

Aritméticos: + , - , * , / , % , ** (adição, subtração, multiplicação, divisão, resto da divisão, exponenciação)

Lógicos: && , || , ! (e, ou, não) , & , | , ~ , ^ (e bit-a-bit, ou bit-a-bit, não bit-a-bit, xor bit-a-bit) and , or , not (tem menor precedência que os 3 primeiros) , xor (ou exclusivo)

String: . (concatenação)

Relacionais: == , > , < , >= , <= , != (contexto numérico) , eq , gt , lt , ge , le , ne (contexto de string)

Outros: >> (shift right) , << (shift left) , x (replicação) , <=> (comparação, no contexto numérico, retorna -1, 0 ou 1) , cmp (comparação, no contexto de string, retorna -1, 0 ou 1) , .. (enumeração) , \ (referência, retorna o endereço associado a um objeto) , -> (dereferência, retorna o valor associado a um endereço) , ?: (if-then-else abreviado), =~ (operador de busca, substituição e translação), !~ (operador de busca, substituição e translação negada)



1.5 Atribuição

O símbolo usado para atribuição é o = (igual). É possível combinar atribuição com alguns dos operadores acima usando: ++, --, +=, -=, *=, /=, %=, **=, &&=, ||=, &=, |=, ^=, .=, x=, >>= e <<=. Os operadores ++ (incremento) e -- (decremento) também podem ser aplicados em strings. Por exemplo, "ab"++ resulta em "ac".

Em Perl, é possível realizar atribuição múltipla, como no exemplo:

($nome, $idade) = ("Lia", 22);

A atribuição múltipla é feita logicamente em paralelo. Dessa forma a sentença ($a, $b) = ($b, $a); é suficiente para trocar os valores das variáveis $a e $b. Ao fazer ($a, @b) = @c; , a variável $a receberá o valor do primeiro elemento do vetor @c e o vetor @b receberá os demais valores contidos no vetor @c.



1.6 Estruturas de controle

A seguir, listamos as estruturas de controle da linguagem. Usamos [ ] (colchetes) para denotar opcionalidade.


Desvios condicionais:

if (EXPRESSÃO) { BLOCO } [[ elseif (EXPRESSÃO) { BLOCO } ] else { BLOCO } ]
unless (EXPRESSÃO) { BLOCO } [ else { BLOCO } ]
do { BLOCO } unless (EXPRESSÃO);

Desvios incondicionais:

return EXPRESSÃO - sai da subrotina retornando o valor da EXPRESSÃO
goto RÓTULO - desvia para a sentença rotulada com RÓTULO
last [RÓTULO] - desvia para a primeira sentença após o laço rotulado com RÓTULO ou para a primeira sentença após o laço corrente, se RÓTULO for omitido
next [RÓTULO] - inicia uma nova iteração do laço rotulado com RÓTULO ou do laço corrente, se RÓTULO for omitido
redo [RÓTULO] - reinicia a iteração corrente do laço rotulado com RÓTULO ou do laço corrente, se RÓTULO for omitido

Podemos definir rótulos da seguinte maneira: RÓTULO: SENTENÇA;

Laços condicionais:

while (EXPRESSÃO) { BLOCO }
do { BLOCO } while (EXPRESSÃO);
until (EXPRESSÃO) { BLOCO }
do { BLOCO } until (EXPRESSÃO);

Laços contados:

for (INICIALIZAÇÃO; CONDICÕES-LIMITE; INCREMENTO) { BLOCO }
foreach VARIÁVEL (LISTA) { BLOCO }

O BLOCO do laço foreach será executado uma vez para cada elemento da LISTA. Em cada iteração do laço, o elemento corrente da LISTA será colocado em VARIÁVEL. Se a VARIÁVEL for omitida, o elemento corrente será colocado na variável especial $_.

Algumas das estruturas de controle acima podem ser utilizadas de forma mais simples:

EXPRESSÃO if EXPRESSÃO;
EXPRESSÃO unless EXPRESSÃO;
EXPRESSÃO while EXPRESSÃO;
EXPRESSÃO until EXPRESSÃO;



1.7 Subrotinas

É possível definir subrotinas em qualquer parte do programa. Ao chamar uma subrotina, os parâmetros podem ou não ser colocados entre parênteses, e se a subrotina ainda não foi definida até aquela altura do programa, o nome da subrotina deve ser precedido de &. Com isto, não há necessidade de definir protótipo de subrotinas. Criamos uma subrotina da seguinte forma:

sub NOME_SUBROTINA { BLOCO }

Note que não declaramos a lista de parâmetros formais. Os parâmetros reais passados para a subrotina, sempre por referência, são colocados no vetor @_. Os parâmetros passados na linha de comando para o programa principal são colocados no vetor @ARGV. A subrotina retorna o valor da última expressão avaliada.



1.8 Funções aritméticas

abs EXPRESSÃO
valor absoluto de EXPRESSÃO
atan2 EXPR1,EXPR2
arco-tangente de EXPR1/EXPR2 em radianos
cos EXPRESSÃO
cosseno de EXPRESSÃO
exp EXPRESSÃO
e (aproximadamente 2.718281) elevado à EXPRESSÃO
int EXPRESSÃO
parte inteira de EXPRESSÃO
log EXPRESSÃO
logaritmo de EXPRESSÃO na base e
rand [EXPRESSÃO ]
número fracionário pseudo-aleatório entre 0 e EXPRESSÃO. Se EXPRESSÃO for omitida, a função retornará um número entre 0 e 1
sin EXPRESSÃO
seno de EXPRESSÃO
sqrt EXPRESSÃO
raiz quadrada de EXPRESSÃO
srand [ EXPRESSÃO ]
inicializa a semente da função de geração de números pseudo-aleatórios. Se a EXPRESSÃO for omitida será assumido um valor baseado no relógio do computador
time
número de segundos transcorridos desde 1º de janeiro de 1970 até a data corrente no relógio do computador



1.9 Funções de conversão

chr EXPRESSÃO
caractere correspondente ao valor de EXPRESSÃO na tabela ASCII
gmtime [ EXPRESSÃO ]
converte EXPRESSÃO (como retornada pelo função time) para um vetor de 9 elementos representando uma data no fuso horário de Greenwich. Se a EXPRESSÃO for omitida, retorna a data do relógio do computador. As posições do vetor têm o seguinte significado: 0: segundos, 1: minutos, 2: horas, 3: dia do mês, 4: mês (0-11), 5: ano corrente menos 1900, 6: dia da semana (0-6), 7: dia do ano, 8: indica se está no horário de verão (0 ou 1)
hex EXPRESSÃO
valor decimal de EXPRESSÃO interpretada como um número hexadecimal
localtime EXPRESSÃO
data, no formato ctime(3) (por exemplo, Thu Dec 16 09:03:33 1999), com base no fuso horário local. Se a EXPRESSÃO for omitida, retorna a data do relógio do computador. No contexto de lista, retorna um vetor semelhante ao retornado pela função gmtime
oct EXPRESSÃO
valor decimal de EXPRESSÃO interpretada como um número octal
ord EXPRESSÃO
código ASCII do primeiro caractere de EXPRESSÃO
pack FORMATO, LISTA
empacota os valores da LISTA de acordo com o FORMATO. Alguns dos caracteres que podem ser usados no FORMATO são:

a
string ASCII
b
string em ordem ascendente
B
string em ordem descendente
c
caractere de 8 bits
C
caractere de 7 bits
f
número de precisão simples em ponto flutuante
d
número de precisão dupla em ponto flutuante
h
número hexadecimal
i
número inteiro com sinal
I
número inteiro sem sinal
l
número inteiro longo com sinal
L
número inteiro longo sem sinal
p
ponteiro para uma string
P
ponteiro para uma estrutura
s
número inteiro curto com sinal
S
número inteiro curto sem sinal
u
string no formato uuencoded
x
byte nulo

unpack FORMATO, EXPRESSÃO
desempacota o valor da EXPRESSÃO usando o FORMATO, resultando num vetor
vec EXPRESSÃO, POS, BITS
trata EXPRESSÃO como um vetor de inteiros sem sinal e retorna o bit na posição POS. BITS tem que estar entre 1 e 32



1.10 Funções de texto

chomp LISTA
remove os caracteres de fim de linha de todos os elementos da LISTA e retorna o número de caracteres removidos
chop LISTA
remove o último caractere de cada elemento da LISTA e retorna o último caractere removido
crypt EXPRESSÃO, SALT
criptografa a EXPRESSÃO. SALT é usado pela função de criptografia (DES - Data Encryption System) e incluído no início do texto cifrado. Não é possível a partir do texto cifrado calcular o texto original
defined VARIÁVEL
retorna verdadeiro se a variável foi definida, falso caso contrário
eval EXPRESSÃO
A EXPRESSÃO é interpretada como um programa perl e executada. É retornado o valor da última expressão avaliada
index STRING, SUBSTRING [, POS]
posição onde começa a primeira ocorrência de SUBSTRING em STRING, procurando a partir da posição POS (ou 1 se POS for omitido). Se SUBSTRING não ocorre em STRING, é retornado -1
length EXPRESSÃO
número de caracteres do valor de EXPRESSÃO
lc EXPRESSÃO
retorna a versão minúscula de EXPRESSÃO
lcfirst EXPRESSÃO
retorna EXPRESSÃO com o primeiro caractere minúsculo
quotemeta EXPRESSÃO
retorna EXPRESSÃO com todos os meta-caracteres contidos em EXPRESSÃO precedidos de \ (barra invertida)
rindex STRING, SUBSTRING [, POS]
posição onde começa a última ocorrência de SUBSTRING em STRING, procurando a partir da posição POS (ou 1 se POS for omitido). Se SUBSTRING não ocorre em STRING, é retornado -1
substr EXPRESSÃO, POS [, TAM]
retorna a substring de EXPRESSÃO iniciada na posição POS e, se TAM for especificado, de comprimento TAM. Se POS for negativo, a posição é contada a partir do final da EXPRESSÃO
uc EXPRESSÃO
retorna a versão maiúscula de EXPRESSÃO
ucfirst EXPRESSÃO
retorna EXPRESSÃO com o primeiro caractere maiúsculo



1.11 Funções para manipulação de vetores e listas

delete $HASH{CHAVE}
remove e retorna o elemento do HASH associada à CHAVE
each %HASH
retorna um vetor de 2 elementos contendo uma chave do HASH e o valor associado àquela CHAVE. Na primeira vez que esta função é chamada, é retornado o primeiro elemento do HASH, e nas chamadas seguintes, serão retornados os próximos elementos do HASH (numa ordem aparentemente aleatória). Quando o HASH tiver sido inteiramente lido, será retornado um vetor nulo
exists $HASH{CHAVE}
retorna verdadeiro se CHAVE existe no HASH, falso caso contrário
grep { BLOCO } LISTA
avalia o BLOCO para cada elemento da lista. O BLOCO pode referenciar o elemento corrente da LISTA através da variável $_. Modificando a variável $_, o elemento corrente da LISTA também é modificado. É retornado um vetor contendo os elementos da LISTA para os quais o BLOCO resulta em verdadeiro. Uma forma alternativa de utilização desta função é: grep SENTENÇA, LISTA
join EXPRESSÃO, LISTA
concatena os elementos da LISTA usando o valor de EXPRESSÃO como separador e retorna a string resultante
keys %HASH
retorna um vetor contendo as chaves do HASH
map {BLOCO} LISTA
executa o BLOCO para cada elemento da lista. O BLOCO pode referenciar o elemento corrente da LISTA através da variável $_. Modificando a variável $_, o elemento corrente da LISTA também é modificado. Uma forma alternativa de utilização desta função é: map SENTENÇA, LISTA
pop @VETOR
remove e retorna o último elemento do VETOR
push @VETOR, LISTA
insere a LISTA no final do VETOR
reverse LISTA
no contexto escalar, inverte cada elemento da LISTA e retorna estes elementos na ordem inversa. No contexto de lista, retorna os elementos da LISTA na ordem inversa
scalar @VETOR
retorna o número de elementos do VETOR
scalar %HASH
retorna verdadeiro, se o HASH tem elementos, ou falso, caso contrário
shift [@VETOR]
remove e retorna o primeiro elemento do VETOR. Se o VETOR for omitido será assumido o vetor @ARGV se a chamada a esta função ocorreu no programa principal, ou o vetor @_ se a chamada ocorreu dentro de uma subrotina
sort [SUBROTINA] LISTA
retorna a LISTA ordenada. A SUBROTINA, que será usada para definir a relação de ordem entre os elementos da LISTA, recebe dois elementos da lista através das variáveis $a e $b e deve retornar um valor menor que zero, se $a precede $b, zero, se $a equivale a $b, ou um valor maior que zero, se $b precede $a
splice @VETOR, POS [, QUANT [, LISTA]]
remove e retorna QUANT elementos do VETOR, a partir da posição POS, substituindo-os pelos elementos da LISTA
split [PADRÃO [, EXPRESSÃO [, LIM]]]
quebra a EXPRESSÃO em substrings usando PADRÃO como separador e retorna um vetor contendo as primeiras LIM substrings obtidas. Se PADRÃO for omitido, será assumido espaço em branco. Se a EXPRESSÃO for omitida, será assumida a variável $_. Se esta função for usada no contexto escalar, ela retornará o número de substrings obtidas e estas substrings serão colocadas no vetor @_
unshit @VETOR, LISTA
insere a LISTA no início do VETOR e retorna o número de elementos do VETOR após esta inserção
values %HASH
retorna um vetor com os valores contidos no HASH



1.12 Funções de entrada e saída

Em operações de entrada e saída, FILEHANDLE deve ser um um manipulador de arquivo aberto com a função open, um manipulador de arquivo pré-definido (STDIN, STDOUT, STDERR, ARGV e DATA) ou uma variável escalar cujo valor é o nome de um manipulador de arquivo. Até o final desta sessão, o termo arquivo deve ser entendido com o arquivo associado ao FILEHANDLE. A expressão <FILEHANDLE> lê o arquivo. Se usado no contexto escalar, lê uma linha do arquivo, No contexto de lista, retorna uma lista na qual os elementos são as linhas do arquivo. A expressão < > lê os arquivos especificados no vetor @ARGV (na ordem em que foram especificados) ou o dispositivo padrão de entrada, se @ARGV for vazio. Listamos a seguir funções para entrada e saída.
binmode FILEHANDLE
faz com que o arquivo seja lido e/ou escrito no modo binário ao invés do modo texto
close FILEHANDLE
fecha o arquivo ou o pipe associado ao FILEHANDLE
eof [FILEHANDLE]
retorna 1 se a próxima leitura do arquivo for retornar o fim do arquivo ou se o arquivo não está aberto. Retorna 0, caso contrário. Se FILEHANDLE for omitido, será assumido o último arquivo lido
fileno FILEHANDLE
retorna o número do descritor do arquivo
flock FILEHANDLE, MODO
Executa a chamada ao sistema flock(2) para o arquivo. O modo pode ser 1 (compartilhado), 2 (exclusivo), 4 (non-blocking) ou 8 (unlock)
getc [FILEHANDLE]
retorna o próximo caractere do arquivo ou uma string nula se o fim do arquivo já tiver sido atingido. Se o FILEHANDLE for omitido, será assumido o dispositivo padrão de entrada (STDIN)
open FILEHANDLE [, ARQ]
abre o arquivo de nome ARQ associando com o manipulador FILEHANDLE. Se ARQ for omitido, uma variável escalar com o mesmo nome do FILEHANDLE deve conter o nome do arquivo. Ao abrir um arquivo é possível especificar o modo de abertura da seguinte forma:

"<ARQ" - somente leitura. Equivale a "ARQ"
">ARQ" - escrita, criando se necessário
">>ARQ" - escrita no final do arquivo
"+>ARQ" - leitura e escrita

É possível executar um programa usando a função open. Chamamos isto de criar um pipe pelo qual o programa Perl e o outro programa podem se comunicar. Para executar o programa de nome CMD fazemos:

"CMD|" - o programa CMD será executado, e seu dispositivo padrão de saída funcionará como o arquivo associado ao FILEHANDLE
"|CMD" - o que for escrito no FILEHANDLE será enviado para o dispositivo padrão de entrada do programa CMD. A execução do programa será iniciada quando o pipe for fechado

print [FILEHANDLE] LISTA
escreve os elementos da LISTA no arquivo. Se FILEHANDLE for omitido será assumido o dispositivo padrão de saída (STDOUT), ou o arquivo selecionado pela função select. Uma outra forma de utilizar esta função é definir uma área de impressão, da seguinte forma:

print <<"ROTULO";
...
ROTULO
read FILEHANDLE, $VAR, QUANT [, POS]
lê QUANT bytes do arquivo, a partir da posição POS, ou da posição corrente, se POS for omitido, e coloca na variável $VAR. Retorna o número de bytes lidos
seek FILEHANDLE, POS, MODO
posiciona o apontador para o arquivo na posição POS. O parâmetro MODO indica a que posição do arquivo POS é relativo: 0, ao início do arquivo; 1, à posição corrente; 2, ao final do arquivo. Se modo for igual a 1 ou 2, POS pode ser negativo. Retorna 1 se o seek foi bem sucedido, 0 caso contrário
select [FILEHANDLE]
seleciona o arquivo como default para as operacoes de escrita. Se FILEHANDLE for omitido, retorna o FILEHANDLE correntemente selecionado
sprintf EXPRESSÃO, LISTA
retorna a EXPRESSÃO interpolada com os elementos da lista. Na EXPRESSÃO podem ser usadas máscaras com a forma %[m[.n]]x onde m e n são números e x pode ser:

c
caractere
d
número inteiro
e
número em notação científica
f
número em ponto flutuante
g
número compacto em ponto flutuante
ld
número inteiro longo
lo
número octal longo
lu
número inteiro longo sem sinal
lx
número hexadecimal longo
o
número octal
s
string
u
número inteiro sem sinal
x
número hexadecimal
X
número hexadecimal com letras maiúsculas

sysread FILEHANDLE, EXPRESSÃO, QUANT [, POS]
lê QUANT bytes do arquivo, a partir da posição POS, ou da posição corrente, se POS for omitido, e coloca na variável $VAR
syswrite FILEHANDLE, $VAR, QUANT [, POS]
escreve QUANT bytes da variável $VAR no arquivo, a partir da posição POS, ou da posição corrente, se POS for omitido
tell [FILEHANDLE]
retorna a posição corrente do arquivo. Se FILEHANDLE for omitido será assumido o último arquivo lido



1.13 Funções para manipulação de arquivos e diretórios

As funções para manipulação de arquivos que operam sobre uma lista de arquivos retornam o número de arquivos para os quais a função foi executada com sucesso.

chdir [EXPRESSÃO]
muda o diretório corrente. Se EXPRESSÃO for omitida será assumido $ENV{HOME} ou $ENV{LOGNAME}
chmod LISTA
modifica as permissões de acesso aos arquivos da LISTA. O primeiro elemento da LISTA precisa ser o código das permissões no modo numérico
chown LISTA
modifica o proprietário e o grupo a que pertencem os arquivos da lista. Os dois primeiros elementos da LISTA precisam ser o o número do usuário (uid) e o número do grupo (gid)
closedir DIRHANDLE
fecha o diretório associado a DIRHANDLE, aberto com a função opendir
link NOVO, VELHO
cria o arquivo NOVO linkado ao arquivo VELHO
lstat ARQUIVO
retorna um vetor de 13 elementos com informações sobre o arquivo. As posições do vetor têm o seguinte significado: 0: número do dispositivo, 1: i-node, 2: permissões, 3: número de links para o arquivo, 4: uid, 5: gid, 6: nome do dispositivo, 7: tamanho em bytes, 8: data do último acesso, 9: data da última modificação, 10: data da última modificação do i-node, 11: tamanho do bloco, 12: número de blocos. ARQUIVO pode ser um filehandle ou o nome de um arquivo. Retorna uma lista nula se a função não for executada com sucesso
opendir DIRHANDLE, DIRETÓRIO
abre o DIRETÓRIO associando-o ao manipulador DIRHANDLE
readdir DIRHANDLE
retorna a próxima entrada (ou uma lista com as próximas entradas, se no contexto de lista) do diretório associado a DIRHANDLE
readlink EXPRESSÃO
retorna o nome do arquivo associado ao valor de EXPRESSÃO, que deve ser o nome de um link simbólico
rename VELHO, NOVO
altera o nome do arquivo VELHO para NOVO
rewinddir DIRHANDLE
posiciona o apontador n primeira entrada do diretório associado a DIRHANDLE
rmdir DIRETÓRIO
apaga o DIRETÓRIO se ele estiver vazio
seekdir DIRHANDLE, n
posiciona o apontador na n-ésima entrada do diretório associado a DIRHANDLE
stat ARQUIVO
semelhante à função lstat, mas se ARQUIVO for um link simbólico serão retornadas as informações relativas ao arquivo associado a ARQUIVO
symlink VELHO, NOVO
cria o arquivo NOVO simbolicamente linkado ao arquivo VELHO
telldir DIRHANDLE
retorna a entrada corrente do diretório associado a DIRHANDLE
truncate ARQUIVO, TAM
trunca o ARQUIVO fazendo com que ele fique com TAM bytes. ARQUIVO pode ser um filehandle ou o nome de um arquivo
ulink LISTA
apaga os arquivos da LISTA
utime LISTA
modifica a data do último acesso e da última modificação dos arquivos da LISTA. Os dois primeiros elementos da LISTA devem ser as datas de acesso e modificação, respectivamente, no formato numérico



1.14 Funções para interação com o sistema operacional

die [LISTA]
escreve o valor da LISTA no dispositivo padrão de erro (STDERR) e encerra o programa retornando o valor corrente da variável $! (número do erro). Se LISTA for omitida será assumido o valor "Died"
exec LISTA
executa o comando do sistema contido na LISTA. Não retorna valor
exit [EXPRESSÃO]
finaliza o programa retornando o valor da EXPRESSÃO ou 0 se a EXPRESSÃO for omitida
getlogin
nome do usuário
getpgrp [PID]
grupo a que pertence o processo de número PID. Se PID for omitido ou se for zero será assumido o processo corrente
getppid
número do processo pai do processo corrente
kill LISTA
envia um sinal para os processos da LISTA. O primeiro elemento da lista deve ser o nome ou o número do sinal
setpgrp [PID]
modifica o grupo a que pertence o processo de número PID. Se PID for omitido ou se for zero será assumido o processo corrente
sleep [EXPRESSÃO]
suspende a execução do programa por um número de segundos equivalente ao valor de EXPRESSÃO ou para sempre se a EXPRESSÃO for omitida. Retorna o número de segundos em que o programa de fato esteve suspenso
syscall LISTA
executa uma chamada ao sistema. O primeiro elemento da LISTA deve ser o nome da chamada ao sistema e os demais elementos os argumentos da chamada
system LISTA
suspende o programa e executa o comando do sistema contido na LISTA. Retorna o código de saída do comando
warn [LISTA]
escreve o valor da LISTA no dispositivo padrão de erro (STDERR). Se a LISTA for omitida será assumido o valor "Warning: something's wrong"
Por fugir ao objetivo deste texto, deixamos de listar algumas poucas funções das categorias abordadas nas seções 1.8 a 1.14, as funções para manipulação de conexões de rede, as funções para iteração com o System V IPC e as funções para obter informações sobre arquivos do sistema e sobre serviços.

Existem ainda operadores para realizar testes em arquivos (como por exemplo, saber se um arquivo é um link simbólico), variáveis e vetores especiais (alguns dos quais já citamos), e variáveis de ambiente. Para obter a documentação completa sobre estes itens, recomendamos a bibliografia citada no início deste capítulo.



1.15 Expressões regulares, busca, substituição e translação

Uma expressão regular é um conjunto de caracteres que serve para simbolizar um conjunto de strings. Por exemplo, a expressão regular a* simboliza todas as strings que iniciam com a letra a. Numa expressão regular, cada caractere representa ele mesmo, exceto alguns caracteres especiais que chamamos de meta-caracteres. Alguns deles são:

.
um caractere qualquer, exceto quebra de linha
$
fim de linha
[...]
um dos caracteres representados dentro dos colchetes. Por exemplo, [ab] simboliza o caractere a ou o caractere b
[^...]
qualquer caractere que não seja um dos caracteres representados por dentro dos colchetes
+
denota repetição do caractere anterior uma ou mais vezes
?
um (ou nenhum) caractere
*
um conjunto (possivelmente vazio) de caracteres
{N,M}
denota repetição do caractere anterior no mínimo N vezes e no máximo M vezes
{N}
denota repetição do caractere anterior N vezes
{N,}
denota repetição do caractere anterior no mínimo N vezes
\w
alfanumérico, incluindo "_"
\W
caractere que não seja alfanumérico
\s
espaço em branco
\S
caractere que não seja espaço em branco
\d
dígito numérico
\D
caractere que não seja dígito numérico
\A
início de uma string
\Z
fim de uma string
\b
início ou fim de uma palavra
\B
caractere que não seja início ou fim de uma palavra

Os demais caracteres precedidos por \ são entendidos conforme a tabela da seção 1.2. Numa operação envolvendo busca de padrões numa string, usando uma expressão regular, as substrings simbolizadas pela expressão regular serão colocadas nas variáveis $1 .. $9.

Para buscar um padrão dentro de uma string usamos o operador m juntamente com o operador =~ (ou !~). Os argumentos para o operador m são uma expressão regular e uma STRING que deve aparecer à esquerda do operador =~ (ou !~). Se a STRING for omitida será assumido o valor da variável $_. Pode-se delimitar a expressão regular com quase qualquer delimitador, mas geralmente usa-se / (barra), caso em que pode-se omitir o m. É possível usar este operador como se fosse uma função, caso em que a expressão regular pode estar ou não dentro de parênteses. Alguns modificadores podem ser usados:

g
busca todas as ocorrências. No contexto escalar, este modificador funciona como um iterador
i
busca case-insensitive
m
trata a STRING como múltiplas linhas
o
interpola as variáveis uma única vez
s
trata a STRING como uma unica linha
x
usa expressões regulares extendidas (que podem conter espaços em branco e comentários)
Serão retornadas todas as substrings da STRING simbolizadas pela expressão regular. Eis alguns exemplos de utilização deste operador:

$anos =~ m/199[0-9]/ , /%[a-fA-F0-9]{2}/sg , $nome !~ m(".s\b")g

Para fazer substituição de padrões dentro de uma string usamos o operador s juntamente com o operador =~ (ou !~). Os argumentos para o operador s são uma expressão regular, uma expressão para substituição e uma STRING que deve aparecer à esquerda do operador =~ (ou !~). Se a STRING for omitida será assumido o valor da variável $_. Pode-se delimitar os argumentos com quase qualquer delimitador, mas geralmente usa-se / (barra). É possível usar este operador como se fosse uma função.

Podem ser usados os mesmos modificadores do operador m e mais o modificador e que faz com que a expressão para substituição seja entendida como código Perl. Todas as substrings da STRING simbolizadas pela expressão regular serão substituídas pelo valor da expressão para substituição e será retornado o número de substituições realizadas ou falso se nenhuma substituição for feita. Eis alguns exemplos de utilização deste operador:

$ano =~ s/1999/2000/ , s/%[a-fA-F0-9]{2}/pack("C",hex($1))/eg , $nome !~ s("caza","casa")g

Para fazer translação de padrões dentro de uma string usamos o operador tr (ou o operador y) juntamente com o operador =~ (ou !~). Os argumentos para o operador tr são uma LISTA DE BUSCA, uma LISTA DE SUBSTITUIÇÃO e uma STRING que deve aparecer à esquerda do operador =~ (ou !~). Se a STRING for omitida será assumido o valor da variável $_. Pode-se delimitar os argumentos com quase qualquer delimitador, mas geralmente usa-se / (barra). É possível usar este operador como se fosse uma função.

Todas os caracteres da STRING contidos na LISTA DE BUSCA serão trocados pelo caractere correspondente na LISTA DE SUBSTITUIÇÃO. Podem ser usados os modificadores c (que indica o complemento da LISTA DE BUSCA), d (que faz com que sejam deletados os caracteres da STRING contidos na LISTA DE BUSCA) e o modificador s (que faz com que as sequências de caracteres da STRING que devem ser traduzidas para o mesmo caractere da LISTA DE BUSCA sejam traduzidas por um único caractere). A função retorna o número de translações realizadas ou falso se nenhuma translação for feita. Eis alguns exemplos de utilização deste operador:

$endereco =~ tr/a/A/ , $nome =~ y("*","x")g

Finalmente, a função study recebe como argumento uma variável e pré-processa esta variável em preparação para realizar operações de busca, substituição e translação.



1.16 Como executar um programa Perl

Para executar um programa Perl é preciso chamar o interpretador Perl e passar o programa fonte como parâmetro, por exemplo:

/usr/bin/perl meuprog.pl

Uma outra forma é colocar na primeira linha do programa fonte o endereço do interpretador Perl precedido de #!, por exemplo:

#!/usr/bin/perl

Neste caso, basta dar permissão de execução para o programa fonte e chamá-lo pela linha de comando. No Unix, para dar permissão de execução para o programa meuprog.pl execute o comando chmod 755 meuprog.pl.




2. O Padrão CGI

Common Gateway Interface (CGI) estabelece um padrão de comunicação entre servidores HTTP e bancos de dados e outras fontes de informação, padrão este conhecido como padrão CGI. Um programa é dito CGI se ele segue o padrão CGI. Estes programas realizam processamento específico de informação e usualmente produzem código HTML ou texto puro, que será enviado ao servidor HTTP, e este por sua vez enviará para o cliente WWW que solicitou o programa CGI.

Desta forma é possível fazer com que a WWW tenha um comportamento dinâmico, com páginas criadas dinamicamente em resposta a requisições específicas formuladas pelos usuários da teia. Tal mecanismo permite um número ilimitado de aplicações, das quais citamos apenas algumas:

Resumindo, o padrão CGI define a maneira pela qual um servidor HTTP passa e recebe informação de um programa.



2.1 Variáveis CGI

Antes de iniciar a execução de um programa CGI, o servidor HTTP inicializa algumas variáveis de ambiente chamadas de variáveis CGI, que servem como importante fonte de informação para o programa CGI. Aqui apresentamos uma tabela contendo as variáveis CGI padrão em um sistema UNIX:

Variável CGI Descrição Exemplo
AUTH_TYPE Tipo de autenticação para acesso Basic
CONTENT_LENGTH Número de bytes usados pelos dados 9
CONTENT_TYPE Tipo dos dados text/plain
GATEWAY_INTERFACE Versão da especificação CGI CGI/1.1
PATH_INFO Caminho a ser usado pelo programa CGI cgi-bin/oracle
PATH_TRANSLATED Caminho absoluto a ser usado pelo programa CGI /usr/cgi-bin/oracle
QUERY_STRING String contendo os dados Nome=Paulo+Dias&Idade=23
REMOTE_ADDR Número IP do cliente 143.107.95.106
REMOTE_HOST Nome da máquina do cliente jaca.ime.usp.br
REMOTE_IDENT Identidade do agente de conexão com o servidor ppp1.ime.usp.br
REMOTE_USER Nome do usuário do programa cliente adriano
REQUEST_METHOD Método de requisição usado pelo cliente POST
SCRIPT_NAME Caminho do aplicativo cgi-bin/post-query.pl
SERVER_NAME Nome do servidor www.ime.usp.br
SERVER_PORT Porta onde a requisição foi recebida 80
SERVER_PROTOCOL Nome e versão do protocolo de requisição HTTP/1.0
SERVER_SOFTWARE Nome e versão do software servidor APACHE/1.1

A variável CONTENT_TYPE especifica o tipo dos dados enviados junto com a requisição HTTP. Os tipos e subtipos registrados são:

Tipo Subtipo Descrição
Application octet-stream Dados binários
text plain, html Texto
multipart mixed, alternative, digest, parallel Múltiplos dados de diferentes tipos
message rfc822, partial, external-body Mensagem encapsulada
image gif, jpeg Imagem
audio basic Som
video mpeg Imagem em movimento

Se uma variável não for instanciada então ela receberá uma string vazia (NULL). O servidor criará também uma variável do tipo HTTP_STRING para conter as informações incluídas no header da requisição enviado pelo browser (STRING denota o prefixo da linha). Por exemplo, se for enviada no header a linha:

Accept: text/html, application/binary, audio/basic, image/gif, video/mpeg

Será criada a ariável HTTP_ACCEPT com o valor text/html, application/binary, audio/basic, image/gif, video/mpeg



2.2 Codificação urlencoded

É importante entender o formato no qual os dados oriundos do preenchimento de um formulário são enviados para um programa CGI. Usualmente, os clientes WWW (browsers) enviam os dados digitados em um formulário usando o seguinte formato, conhecido como application/x-www-form-urlencoded (ou simplesmente urlencoded):

campo1=valor1&campo2=valor2&campo3=valor3 ...

Note que os campos são separados por & (e comercial) e o nome do campo e o valor associado àquele campo são separados por = (igual). Os espaços em branco digitados nos campos do formulário são convertidos em + (mais). Os caracteres acentuados, o c cedilha e os caracteres ` ' ~ ^ " ! ? , ; : # $ % & = + / | \ ( ) [ ] { } < > são convertidos para sua representação na tabela ASCII, em hexadecimal, precedida do símbolo % (veja no Apêndice 2 a tabela ASCII HTML).

Por exemplo, considere o formulário a seguir:

Ao definir o valor João da Silva para o campo nome e 29/02/1972 para o campo nascimento, o browser enviará os dados do formulário da seguinte forma:

nome=Jo%E3o+da+Silva&nascimento=29%2F02%2F%1972

O programa CGI deve ser capaz de converter esta string para uma lista de variáveis e valores legíveis. O código Perl a seguir é capaz de fazer esta conversão:

#!/usr/bin/perl

# checando qual o método usado para enviar os dados
if ($ENV{REQUEST_METHOD} eq 'POST')
  { # se foi usado o método POST pegar os dados do STDIN
    read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); }
else
  { # de outro modo pegar os dados da variável QUERY_STRING
    $buffer = $ENV{QUERY_STRING}; }

# separando cada campo e seu valor 
@pares = split(/&/, $buffer);

foreach $par (@pares)
  { # jogando o nome do campo na variável campo e seu valor na variável valor
    ($campo, $valor) = split("=", $par);

    # convertendo + em espaço em branco 
    $valor =~ tr/+/ /g;

    # convertendo os caracteres em hexadecimal para sua representaçao ASCII
    $valor =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    # colocando no hash conteudo os valores dos campos, usando os nomes dos
    # campos como chaves
    $conteudo{$campo} = $valor;
  }



2.3 Passando dados para programas CGI

Umas das formas de passar dados para um programa CGI é usando o método GET. No método GET um URL é seguido do símbolo ? após do qual vem uma string contendo as informações a serem passadas para o programa CGI. Como os dados digitados no formulários serão enviados para o programa CGI como parte do URL, ao usar o método GET não é possivel ocultar os dados através de criptografia. Sempre que for usado o método GET, o servidor HTTP colocará uma string contendo os dados do formulário, no formato urlencoded, na variável de ambiente QUERY_STRING.

Outra maneira de passar dados para um programa CGI é usando o método POST. Neste caso o servidor HTTP colocará os dados do formulário no dispositivo padrão de entrada (STDIN) do programa CGI. O que define o método de envio dos dados é o valor atribuído ao atributo method do marcador form quando da criação do formulário.



2.4 Saída de um programa CGI

Um programa CGI sempre deve retornar algo para o servidor HTTP que o chamou. Esta saída deve ser enviada para seu dispositivo padrão de saída (STDOUT). A saída de um programa CGI pode ser código HTML, texto puro, uma imagem, um som, um arquivo binário, etc...

O formato mais utilizado pelos programas CGI para enviar sua saída é chamado de parsed header output. De fato, só é requerido dos servidores HTTP entender este formato. Este tipo de saída consiste de um cabeçalho e o corpo da saída, separados por um linha em branco. O cabeçalho deve obrigatoriamente conter uma linha iniciada com Content-type:. O restante desta linha deve ser a especificação do tipo e subtipo de mídia contidos no corpo da saída, conforme a tabela da seção 2.1. Por exemplo: Content-type: text/html.



2.5 Exemplos de programas CGI

Examinaremos dois exemplos de programas CGI escritos em Perl. O primeiro deles recebe como dados um nome e uma senha, verifica se este nome e senha constam em um cadastro e em caso afirmativo envia o programa transgif. O segundo exemplo recebe os dados de um formulário de pedidos, devolve uma página para o usuário que preencheu o formulário confirmando o recebimento do pedido e envia uma mensagem de correio eletrônico com os dados legíveis para o encarregado de processar os pedidos.

Exemplo 1:

Considere o formulário abaixo e o código HTML que o gerou:

    <form action=/cgi-bin/autenticacao.pl method=POST> Nome: <input name=usuario> Senha: <input type=password name=senha size=8> <input type=submit> </form>

Aqui temos o código do programa autenticacao.pl:

#!/usr/bin/perl

# checando qual o método usado para enviar os dados
if ($ENV{REQUEST_METHOD} eq 'POST')
  { # se foi usado o método POST pegar os dados do STDIN
    read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); }
else
  { # de outro modo pegar os dados da variável QUERY_STRING
    $buffer = $ENV{QUERY_STRING}; }

# separando cada campo e seu valor 
@pares = split(/&/, $buffer);

foreach $par (@pares)
  { # jogando o nome do campo na variável campo e seu valor na variável valor
    ($campo, $valor) = split("=", $par);

    # convertendo + em espaço em branco 
    $valor =~ tr/+/ /g;

    # convertendo os caracteres em hexadecimal para sua representaçao ASCII
    $valor =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    # colocando no hash conteudo os valores dos campos, usando os nomes dos
    # campos como chaves
    $conteudo{$campo} = $valor;
  }

# criando o pipe onde buscamos no arquivo cadastro o usuário e sua senha
open(BUSCA,"grep -x '$conteudo{usuario},$conteudo{senha}' cadastro |");

if (<BUSCA> ne "")
  { # senha correta, enviando header para transmissão de arquivo binário
    print "Content-Type: application/octet-stream\n\n";

    # enviando o arquivo /usr/local/bin/transgif
    open(ARQ,"/usr/local/bin/transgif");
    while (<ARQ>) { print $_; } }
else
  { # senha incorreta, enviando documento HTML com mensagem de erro
    print "Content-type: text/html\n\n";
    print "<h1>Usuário não cadastrado ou senha incorreta !\n" }

close(BUSCA);


Exemplo 2:

Neste exemplo temos um formulário para compra de um computador. A seguir temos o formulário e o código HTML usado para gerá-lo:



    <form action=/cgi-bin/pedido.pl method=GET> Produto Desejado: <select name=produto> <option> Pentium 16mb RAM 1.2gb HD Multimidia <option> Pentium MMX 200 Mhz 32mb RAM 4.1gb HD Multimidia <option> Pentium II 400 Mhz 64mb RAM 8.7gb HD Multimidia <option> Pentium III Xeon 800 Mhz 256mb RAM 12.3gb HD Multimidia </select><p> Nome: <input name=comprador size=30> Telefone: <input name=fone size=14><br> Endereço: <input name=endereco size=50><brp> Cartão de Crédito: <input type=radio name=cartao value=Amex> American Express <input type=radio name=cartao value=Credicard> Credicard/Mastercard <input type=radio name=cartao value=Diners> Diners <input type=radio name=cartao value=Visa> Visa<br> Número do Cartão: <input name=numero size=16> Data de Validade: <input name=validade size=8><br> <center><input type=submit value="Enviar Pedido"></center> </form>

O programa abaixo, pedido.pl, processa o formulário enviando uma confirmação para o cliente e uma mensagem de correio eletrônico com os dados do pedido para o encarregado dos pedidos (vendedor@compushop.com.br).

#!/usr/bin/perl

# checando qual o método usado para enviar os dados
if ($ENV{REQUEST_METHOD} eq 'POST')
  { # se foi usado o método POST pegar os dados do STDIN
    read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); }
else
  { # de outro modo pegar os dados da variável QUERY_STRING
    $buffer = $ENV{QUERY_STRING}; }

# separando cada campo e seu valor 
@pares = split(/&/, $buffer);

foreach $par (@pares)
  { # jogando o nome do campo na variável campo e seu valor na variável valor
    ($campo, $valor) = split("=", $par);

    # convertendo + em espaço em branco 
    $valor =~ tr/+/ /g;

    # convertendo os caracteres em hexadecimal para sua representaçao ASCII
    $valor =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    # colocando no hash conteudo os valores dos campos, usando os nomes dos
    # campos como chaves
    $conteudo{$campo} = $valor;
  }

# gerando o documento HTML com a confirmação do pedido
print "Content-type: text/html\n\n";
print <<"HTML";
<html>
<head><title>Compushop - Confirmacao de Pedido</title>
<body bgcolor=white>
<h1>Compushop - Confirmação de Pedido</h1>
<hr>Confirmamos o recebimento do seu pedido:<p>

Produto: $conteudo{'produto'}<p>
Nome: $conteudo{'comprador'}<p>
Telefone: $conteudo{'fone'}<p>
Endereço: $conteudo{'endereco'}<p>
Cartão de Crédito: $conteudo{'cartao'}<p>
Número do Cartão: $conteudo{'numero'}<p>
Validade do Cartão: $conteudo{'validade'}<p>
</body>
</html>
HTML

# agora criando a mensagem a ser enviada para vendedor@compushop.com.br
chop($data = `date`);
# criando o pipe para enviar a mensagem
open(MAIL, "| /usr/bin/mail vendedor\@compushop.com.br")
# selecionando o pipe MAIL como saída padrão
select(MAIL);

# enviando a mensagem
print <<"PEDIDO";
Date: $data
To: vendedor\@compushop.com.br
Subject: Pedido de Compra

Produto: $conteudo{produto}
Nome: $conteudo{comprador}
Telefone: $conteudo{fone}
Endereço: $conteudo{endereco}
Cartão de Crédito: $conteudo{cartao}
Número do Cartão: $conteudo{numero}
Validade do Cartão: $conteudo{validade}
PEDIDO

close(MAIL);

Ao escrever programas CGI é preciso atentar para a segurança impedindo que pessoas mal-intencionadas usem meta-caracteres para obter resultados indesejáveis. Suponha, por exemplo, que um determinado programa CGI recebe a string "%7Crm -rf *", decodifica esta string transformando-a em "|rm -rf *" e envia esta string como parâmetro para um programa qualquer. No UNIX isto significa que todos os arquivos do diretório corrente e seus subdiretórios serão definitivamente apagados. Este é apenas um exemplo do que pode acontecer se relaxarmos na segurança ao escrever um programa CGI.



2.6 Cookies

Cookies proveêm um mecanismo que permite a um servidor HTTP enviar informação para um browser, que por sua vez poderá armazenar ou não esta informação na máquina cliente. Todo cookie possui nome, valor e um servidor associado a ele. Podemos manipular (enviar, receber, processar, alterar e remover) cookies usando javascript ou programas CGI. Explicaremos a seguir como manipular cookies através de programas CGI.

Para enviar um cookie, basta que o programa CGI inclua no header da resposta enviada ao browser uma linha com a seguinte sintaxe:

Set-Cookie: NOME=VALOR [;EXPIRES=DATA] [;DOMAIN=DOMÍNIO] [;PATH=CAMINHO] [;SECURE]

O parâmetro NOME é o nome do cookie e VALOR é a informação associada a ele. Esta informação deve ser um conjunto de caracteres que não pode conter vírgula, ponto-e-vírgula ou espaço em branco. A DATA determina até quando o cookie deve ser armazenado. Se for omitida, o browser armazenará o cookie na memória, mas não no disco, de forma que ao fechar o browser o cookie será apagado. O parâmetro DATA deve ser uma data válida, no seguinte formato:

dia da semana, DD-MMM-AAAA HH:MM:SS GMT

Por exemplo:

Wednesday, 16-Feb-2000 23:12:40 GMT

O valor do parâmetro DOMÍNIO deve ser um domínio (computador ou rede) com no mínimo 2 ou 3 pontos. Qualquer domínio dentro de COM, EDU, NET, ORG, GOV, MIL e INT deve ter pelo menos 2 pontos; todos os outros domínios precisam ter pelo menos 3 pontos. Ao definir um DOMÍNIO, é obrigatório que o programa CGI esteja sendo executado por um servidor dentro deste DOMÍNIO. Se este parâmetro for omitido, será assumido o nome (ou número IP) do servidor onde o programa CGI foi executado.

O parâmetro CAMINHO indica um prefixo do caminho de um diretório. Se omitido, será assumido o diretório do programa CGI que enviou o cookie (como descrito no header HTTP). Finalmente, o parâmetro SECURE indica que o cookie só deve ser enviado pelo browser se for usado o protocolo https. A seguir temos um exemplo de como enviar um cookie:

Set-Cookie: ID=143; EXPIRES=Friday, 31-Mar-2000 23:12:40 GMT; DOMAIN=.ime.usp.br; PATH=/cgi-bin;

O nome deste cookie é ID e seu valor é 143. Ele será válido até às 23:12:40 GMT de 31/mar/2000. Quando o browser que recebeu este cookie requisitar qualquer arquivo dentro de um diretório cujo caminho tenha /cgi-bin como prefixo, e que esteja em um servidor dentro do domínio ime.usp.br, ele enviará junto com a requisição o nome e o valor do cookie, da seguinte forma:

Cookie: ID=143

Como falamos anteriormente, os cookies serão recebidos pelo programa CGI através da variável de ambiente HTTP_COOKIE. O Netscape Navigator pode armazenar até 300 cookies, no máximo 20 por servidor, com até 4 kb cada um. Se um cookie exceder 4 kb, seu VALOR será truncado. Ao exceder o limite de 300 cookies no total ou de 20 cookies por servidor, o Netscape remove o cookie que tiver sido usado há mais tempo. Se o browser tiver que enviar vários cookies junto com uma requisição, eles serão enviados na mesma linha, separados por ponto-e-vírgula:

Cookie: nome1=valor1; nome2=valor2 ...

Se um programa CGI quiser remover um cookie, basta reenviar este cookie com o mesmo NOME e CAMINHO, mas com uma data de expiração passada. Ao reenviar um cookie com o mesmo NOME e CAMINHO, o seu valor é alterado.





Apêndice 1: Tabela de Acentos e Caracteres Especiais

Ao usar um editor de texto que permita acentuação para criar um página, corremos o risco dos acentos não serem interpretados corretamente por alguns browsers, em especial browsers instalados em países onde não se utiliza acentuação, como os Estados Unidos, por exemplo. Se quisermos garantir que a acentuação da nossa página vai ser universalmente entendida devemos usar as entities. Nas entities faz diferença usar caracteres maiúsculos ou minúsculos. Na verdade entities é o único caso onde a HTML é case-sensitive. É verdade que é muito trabalhoso colocar as entities ao invés de usar diretamente os caracteres acentuados, mas alguns editores (como o emacs, por exemplo) permitem que digitemos os caracteres acentuados e eles se encarregam de convertê-los para as entities correspondentes. A tabela abaixo especifica as entities usadas para conseguir letras acentuadas, e alguns caracteres especiais como c cedilha, símbolo de copyright, caracteres nórdicos, etc.

Tabela de Acentos e Caracteres Especiais em HTML usando entities
Á &Aacute; È &Egrave; ô &ocirc; Ç &Ccedil;
á &aacute; è &egrave; Ò &Ograve; ç &ccedil;
 &Acirc; Ë &Euml; ò &ograve;
â &acirc; ë &euml; Ø &Oslash; Ñ &Ntilde;
À &Agrave; Ð &ETH; ø &oslash; ñ &ntilde;
à &agrave; ð &eth; Õ &Otilde;
Å &Aring; õ &otilde; Ý &Yacute;
å &aring; Í &Iacute; Ö &Ouml; ý &yacute;
à &Atilde; í &iacute; ö &ouml;
ã &atilde; Î &Icirc; " &quot;
Ä &Auml; î &icirc; Ú &Uacute; < &lt;
ä &auml; Ì &Igrave; ú &uacute; > &gt;
Æ &AElig; ì &igrave; Û &Ucirc; & &amp;
æ &aelig; Ï &Iuml; û &ucirc;
ï &iuml; Ù &Ugrave; ® &reg;
É &Eacute; ù &ugrave; © &copy;
é &eacute; Ó &Oacute; Ü &Uuml; Þ &THORN;
Ê &Ecirc; ó &oacute; ü &uuml; þ &thorn;
ê &ecirc; Ô &Ocirc; ß &szlig;

Apêndice 2: Tabela ASCII HTML

É possível conseguir acentuação, os caracteres especiais já vistos e ainda outros usando o código ASCII precedido de &#. A tabela a seguir mostra os códigos e o caracteres correspondentes.

Tabela ASCII HTML
&#33; ! &#65; A &#97; a &#163; £ &#195; Ã &#227; ã
&#34; " &#66; B &#98; b &#164; ¤ &#196; Ä &#228; ä
&#35; # &#67; C &#99; c &#165; ¥ &#197; Å &#229; å
&#36; $ &#68; D &#100; d &#166; ¦ &#198; Æ &#230; æ
&#37; % &#69; E &#101; e &#167; § &#199; Ç &#231; ç
&#38; & &#70; F &#102; f &#168; ¨ &#200; È &#232; è
&#39; ' &#71; G &#103; g &#169; © &#201; É &#233; é
&#40; ( &#72; H &#104; h &#170; ª &#202; Ê &#234; ê
&#41; ) &#73; I &#105; i &#171; « &#203; Ë &#235; ë
&#42; * &#74; J &#106; j &#172; ¬ &#204; Ì &#236; ì
&#43; + &#75; K &#107; k &#173; ­ &#205; Í &#237; í
&#44; , &#76; L &#108; l &#174; ® &#206; Î &#238; î
&#45; - &#77; M &#109; m &#175; ¯ &#207; Ï &#239; ï
&#46; . &#78; N &#110; n &#176; ° &#208; Ð &#240; ð
&#47; / &#79; O &#111; o &#177; ± &#209; Ñ &#241; ñ
&#48; 0 &#80; P &#112; p &#178; ² &#210; Ò &#242; ò
&#49; 1 &#81; Q &#113; q &#179; ³ &#211; Ó &#243; ó
&#50; 2 &#82; R &#114; r &#180; ´ &#212; Ô &#244; ô
&#51; 3 &#83; S &#115; s &#181; µ &#213; Õ &#245; õ
&#52; 4 &#84; T &#116; t &#182; &#214; Ö &#246; ö
&#53; 5 &#85; U &#117; u &#183; · &#215; × &#247; ÷
&#54; 6 &#86; V &#118; v &#184; ¸ &#216; Ø &#248; ø
&#55; 7 &#87; W &#119; w &#185; ¹ &#217; Ù &#249; ù
&#56; 8 &#88; X &#120; x &#186; º &#218; Ú &#250; ú
&#57; 9 &#89; Y &#121; y &#187; » &#219; Û &#251; û
&#58; : &#90; Z &#122; z &#188; ¼ &#220; Ü &#252; ü
&#59; ; &#91; [ &#123; { &#189; ½ &#221; Ý &#253; ý
&#60; < &#92; \ &#124; | &#190; ¾ &#222; Þ &#254; þ
&#61; = &#93; ] &#125; } &#191; ¿ &#223; ß &#255; ÿ
&#62; > &#94; ^ &#126; ~ &#192; À &#224; à &#256; Ā
&#63; ? &#95; _ &#161; ¡ &#193; Á &#225; á
&#64; @ &#96; ` &#162; ¢ &#194; Â &#226; â