Os FORMULÁRIOS fazem com que as páginas WWW fiquem interactivas. As páginas podem ser
muito bem construídas, podem ter bom aspecto mas, sem formulários, servem apenas para uma
simples leitura.
Ao navegar na Internet, já deve ter visto e preenchido vários exemplos de formulários . Os formulários
são estruturas compostas por vários objectos GUI (Graphical User Interface): campos de texto, campos
senha, botões, checkboxes, menus pull-down, onde se podem solicitam informações como o nome, o
endereço, onde o utilizador pode fazer uma escolha entre várias alternativas, etc. Os mais populares
são os formulários dos sites de pesquisas, onde se digita uma determinada palavra e, como resultado,
são indicados sites relacionados com a mesma.
Quando um utilizador pressiona um botão a indicar que o formulário deve ser enviado, a informação aí
presente é normalmente direccionada para um servidor para processamento através de um
programa CGI. Contudo, se simplesmente se quiser ter os dados enviados para um endereço de e-
mail, terá de se usar a Action mailto.
Neste módulo começamos por analisar a marca (tag) <FORM>, depois vamos explicar as marcas que
desenham os elementos de entrada de dados: <INPUT>, <SELECT> e <TEXTAREA>, e passamos em
seguida à construção dos scripts, que são os programas que tratam esses dados, oferecendo os
serviços desejados (acesso a bases de dados, envio de e-mail, etc.).
Marca FORM
A marca <FORM> delimita um formulário, e contém uma sequência de elementos de entrada e de
formatação do documento:
</FORM>
Os formulários podem conter qualquer formatação - parágrafos, listas, tabelas, imagens - excepto
outros formulários. Um documento pode conter múltiplos elementos <form>, mas os elementos <form>
não podem estar encaixados.
Action
Especifica o URL do script (programa) que irá receber os dados do formulário, decodificá-los e
processar a resposta. Se estiver a referenciar um programa que existe no mesmo servidor que o
formulário, não precisa incluir o URL completo:
Define o método de transmissão. Os métodos usados actualmente são o GET e o POST. Ambos os
métodos transferem dados do browser para o servidor, com a seguinte diferença básica:
POST - os dados introduzidos fazem parte do corpo da mensagem enviada para o servidor;
GET - os dados introduzidos fazem parte do URL associado à consulta enviada para o servidor;
Enctype
Indica o tipo de codificação dos dados enviados através do formulário. O tipo de codificação default é
application/x-www-form-urlencoded, onde:
Caso queira receber o conteúdo do formulário por correio electrónico, deve adicionar
ENCTYPE="TEXT/PLAIN" e ACTION="Mailto: endereço_email".
Exemplo:
Campo de texto
A marca <INPUT> permite a entrada de texto, quando o atributo type="text". O valor text é assumido
por defeito quando o atributo type não é indicado.
Sintaxe:
<INPUT TYPE="text" NAME="nome_campo" VALUE="valor_inicial" SIZE=tamanho1
MAXLENGTH=tamanho2>
Atributos:
TYPE - tipo da entrada;
NAME - variável onde será armazenado o texto;
VALUE - valor inicial atribuido à variável name;
SIZE - tamanho visível do campo. O valor padrão é 20;
MAXLENGTH - número máximo de caracteres do campo.
Nota: Os atributos Size e Maxlength só são válidos nas marcas text e password;
Uma outra possibilidade de definir esta marca é através de editores de HTML: FrontPage, HomeSite,
HTMLPad, que geram o código HTML correspondente.
No caso do HomeSite
Campo senha
Na marca <INPUT> com o atributo type="password" os caracteres introduzidos são substituidos por
asteriscos, razão pela qual é normalmente utilizado para a introdução de senhas e palavras-chave.
Desta forma impede-se a visualização do texto que está a ser introduzido.
Sintaxe:
<INPUT TYPE="password" NAME="nome_campo" VALUE="valor_inicial" SIZE=tamanho1
MAXLENGTH=tamanho2>
Atributos:
TYPE - tipo da entrada;
NAME - nome atribuido ao campo;
VALUE - texto que pretendemos atribuir por defeito ao campo name;
SIZE - tamanho visível do campo. O valor padrão é 20;
MAXLENGTH - número máximo de caracteres do campo.
Sintaxe:
<TEXTAREA NAME="nome_campo" ROWS=x COLS=y> Texto </TEXTAREA>
Atibutos:
NAME - variável onde será armazenado o texto digitado;
COLS - número de colunas;
ROWS - número de linhas.
ferramentas forms
Campo "hidden"
A marca <INPUT> com o atributo type="hidden" permite definir dados que são passados a um
programa CGI mas não aparecem ao utilizador do formulário. Este campo serve para memorizar
valores durante um diálogo com o utilizador.
Por exemplo, um site que permita encomendar produtos pode apresentar ao utilizador vários
formulários, listando os diferentes produtos que podem ser encomendados, e no último formulário
apresenta uma lista com todos os produtos que o utilizador seleccionou.
Sintaxe:
<INPUT TYPE="hidden" NAME="nome_variavel" VALUE="valor_inicial">
Atributos:
TYPE - tipo do campo a ser utilizado;
NAME - variável que contém o valor a ser enviado para o script CGI;
VALUE - valor a ser passado para o script CGI.
Botão "checkbox"
Várias marcas <INPUT> com o atributo type="checkbox" são utilizadas quando se pretende seleccionar
mais do que uma opção de um conjunto. Um checkbox possui dois estados "seleccionado" e "não
seleccionado".
Sintaxe:
<INPUT TYPE="checkbox" NAME="variavel" VALUE="xxx"> descrição
Atributos:
TYPE - tipo de entrada;
NAME - variável que armazenará o valor das opções seleccionadas;
VALUE - valor que será adicionado à variável name quando esta opção for seleccionada;
descrição - texto que aparece ao lado do checkbox.
Sintaxe:
<INPUT TYPE="radio" NAME="variavel" VALUE="xxx"> descrição
Atributos:
TYPE - tipo do campo a ser utilizado;
NAME - variável que armazenará o valor da opção seleccionada;
descrição - texto que aparece ao lado do radio button.
Botão "reset"
Este comando restaura os valores iniciais das entrada de dados.
Sintaxe:
<INPUT TYPE="reset" VALUE="xxx">
Atributos:
TYPE - tipo de botão a ser utilizado;
VALUE - rótulo do botão.
Login:
<FORM>
<INPUT TYPE="text" NAME=login> Password:
<Password: <INPUT TYPE="password">
<INPUT TYPE="reset" VALUE="Apaga tudo!>
</FORM> Apaga tudo!
Redefinir
Se o atributo VALUE não for indicado é criado um botão com o seguinte aspecto:
seleccionar
Botão "submit"
Nos formulários a marca <INPUT> com atributo type="Submit" é utilizada para enviar os dados
introduzidos pelo utilizador para um script CGI.
Sintaxe:
<INPUT TYPE="submit" VALUE="xxx">
Atributos:
TYPE - tipo de botão a ser utilizado;
VALUE - rótulo do botão;
Enviar
Se o atributo VALUE não for indicado é criado um botão com o seguinte aspecto:
Botão "image"
A marca <INPUT> com o atributo type ="image" é utilizada para mapas activos (e outras imagens
clicáveis). Quando este botão é clicado, o formulário é submetido e as coordenadas (x,y) do pixel
seleccionado (posição do rato) são guardadas em variáveis que são enviadas juntamente com os
dados introduzidos no formulário para um script CGI.
Esta marca permite identificar regiões num mapa ou objectos numa imagem. Compare com a nocão
de Usermap.
Sintaxe:
<INPUT TYPE="image" NAME="Imagem" SRC="imagem.jpg" >
Atributos:
TYPE - tipo do botão;
NAME - nome da variável;
SRC - nome do ficheiro que contém a imagem.
<FORM>
<INPUT TYPE="image" NAME="Imagem"
SRC="imagens/input_image.jpg">
</FORM>
Escolha única
A marca <SELECT> permite seleccionar uma opção de um conjunto de itens. É possível estabelecer
uma escolha-padrão, através do atributo selected.
Sintaxe:
<SELECT NAME=".." SIZE=y >
<OPTION> Item 1
<OPTION selected> Item 2
.
<OPTION> Item N
</SELECT>
Atributos:
NAME - variável à qual vai ser atribuído o item seleccionado;
OPTION - vários itens do menu;
SIZE - quantidade de itens visíveis na janela.
Escolha múltipla
A marca <SELECT> com o atributo MULTIPLE permite seleccionar uma ou várias opções de um
conjunto de itens. É possível estabelecer uma escolha-padrão, através do atributo selected.
Sintaxe:
<SELECT NAME=".." SIZE=y MULTIPLE>
<OPTION> Item 1
<OPTION selected> Item 2
.
<OPTION> Item N
</SELECT>
Atributos:
NAME - variável à qual vai ser atribuído o item seleccionado;
OPTION - vários itens do menu;
SIZE - quantidade de itens visíveis na janela;
MULTIPLE - a utilização deste atributo torna o menu de múltipla escolha.
NOTA: Para seleccionar mais do que um item utilizar a tecla CRT ou a tecla SHIFT no caso de serem seguidos.
No caso do HomeSite, na barra de ferramentas forms
seleccionar
CGI (Common Gateway Interface), também chamado de script CGI, é um programa que é executado
num servidor WWW, em resposta a um pedido de um browser. Geralmente o script é uma interface
entre o servidor e outro programa do sistema. Estes programas podem ser tanto scripts como
programas compilados.
Web Gateways são programas ou scripts que recebem pedidos, e retornam um documento com os
resultados correspondentes. Esse documento pode existir previamente, ou pode ser gerado pelo script
especialmente para responder ao pedido. O servidor pode fornecer informação que não é directamente
legível pelo cliente (ex: uma pergunta em SQL), as gateways funcionam como uma interface entre os
dois.
Suponhamos por exemplo que temos uma base de dados Oracle que contem estatísticas dos
resultados obtidos pelos alunos de mestrado nas disciplinas do 2º semestre e que queremos mostrar
esta informação na web. É claro que não podemos enviar o ficheiro da base de dados directamente ao
cliente (isto é abrir o URL associado com o ficheiro pois os dados não teriam qualquer significado).
Nesta situação a CGI providência uma solução para o problema. Podemos usar uma linguagem como
o OraPerl ou uma extensão DBI ao Perl para formular questões em SQL e assim ler a informação
contida na base de dados. Depois de ter a informação, podemos formatá-la e enviá-la ao cliente. Neste
caso o programa CGI serve como gateway para uma base de dados Oracle.
Em síntese, para que são usados os scripts CGI ?
Estes scripts são programas que tratam pedidos dos clientes (browsers). Estes pedidos são
processados e são gerados documentos que são enviados de volta aos clientes. Os browsers, por sua
vez, interpretam-nos e apresentam-nos no écran. O servidor HTTP pode fornecer dados que os
clientes não conseguem interpretar directamente, uma vez estes scripts CGI servem de gateway entre
um cliente e, por exemplo, uma base de dados.
Um script CGI pode ser um ficheiro de comandos, interpretáveis pelo S.O., ou pode ser escrito em
qualquer linguagem que produza um ficheiro executável. Mas as linguagens devem ser compatíveis
com a plataforma sob a qual o servidor está correr, isto é, não importa a linguagem em que o programa
é escrito, desde que tenha permissão e recursos para correr na máquina.
As linguagens mais usadas são:
C/C++
PERL
TCL
Bourne Shell, C Shell (em ambiente UNIX)
VB Script (em ambiente Windows)
Apesar de se poder usar qualquer linguagem para programar CGI's, algumas são mais adequadas do
que outras. Antes de escolher uma linguagem devemos considerar as seguintes características:
- Facilidade que a linguagem tem de aceder a variáveis de ambiente (em Unix) uma vez que
estas variáveis constituem o input para o programa CGI.
Métodos de transmissão
O protocolo HTTP (HiperText Transfer Protocol) utiliza vários métodos de manipulação e organização
dos dados. Actualmente, os dois métodos mais utilizados para submeter dados de formulários são o
GET e o POST. Ambos os métodos transferem dados do browser para o servidor, a maior diferença
entre eles é a maneira como a informação é passada para o programa CGI:
GET
POST
Os dados introduzidos num formulário fazem parte do corpo da mensagem enviada para o
servidor;
Enquanto o método GET passa a informação através de variáveis de ambiente , o POST envia
os dados para o programa CGI através do standard input (entrada padrão), como uma string de
comprimento especificado na variável de ambiente CONTENT_LENGTH;
Faz 2 ligações ao servidor, uma para contactar o servidor e outra para enviar os parâmetros;
Noutras palavras, se o servidor receber um pedido de um formulário usando o POST, ele sabe
que tem que continuar "à espera" do resto da informação;
Pode encriptar os dados;
É possível transferir uma grande quantidade de dados.
A vantagem do GET é que permite aceder ao programa CGI com uma query sem utilizar um formulário,
basicamente estamos a passar parâmetros para um programa.
Exemplo: <A HREF="/cgi-bin/program.pl?user=Larry%20Bird&age=35&pass=testing"> Programa CGI
</A>
A maior desvantagem do Get são a falta de segurança e o facto de ter de haver algum cuidado para
que o browser ou o servidor não trunquem a informação que exceda o número de caracteres permitido.
A maior vantagem do método Post é o tamanho da query poder ser ilimitado. Para obter informação
através do método POST, o programa CGI lê do standard input, por essa razão não é possivel aceder
à CGI sem utilizar um formulário.
Variavéis de Ambiente
Quando um programa CGI é chamado, dispõe de informação sobre o cliente, sobre o servidor e de
dados do formulário que o utilizador forneceu. A maior parte da informação sobre o cliente e o servidor
é colocada em variáveis de ambiente. Os dados do formulário são incorporados numa variável de
ambiente (método GET) ou incluídos no corpo do pedido (método POST), como já se referiu.
Os scripts têm acesso a essas variáveis através da interface CGI. Existem variáveis de ambiente
inicializadas no momento em que o servidor executa o programa CGI solicitado e outras que não estão
ligadas a requisições específicas e estão sempre inicializadas: SERVER_SOFTWARE,
SERVER_NAME, GATEWAY_INTERFACE.
Uma das informações mais importantes que o servidor passa ao programa CGI é o nome do cliente (ou
browser). Diferentes browsers web suportam diferentes tags HTML, assim se, por exemplo, o programa
CGI gera uma imagem tem que ser sensível ao facto de alguns browsers suportarem a marca <IMG> e
outros não. Para além disso, alguns browsers suportam imagens JPEG e GIF e outros nem sequer
suportam imagens. Usando a variável de ambiente HTTP-USER-AGENT podemos determinar qual o
browser que está a ser usado.
A maioria dos servidores esperam que os programas e scripts CGI estejam num directório
chamado cgi-bin e/ou que tenham uma certa extensão (.cgi). Na maioria dos casos, um pedido de um
programa CGI (um utilizador abre um URL associado a uma CGI) é semelhante ao pedido de um outro
qualquer documento. A diferença é que, quando o servidor reconhece que o endereço pedido é de uma
CGI, não retorna o conteúdo do ficheiro e em vez disso tenta executar o programa.
Variáveis de ambiente;
Entrada padrão (stdin, na nomenclatura Unix), esta forma de passagem de dados para os
scripts serve para submissão de pedidos de formulários, através do método POST.
Os dados chegam numa string constituída por pares nome=valor, separados pelo caracter & . Cada par
está codificado, ou seja, os espaços estão substituídos por "+" e alguns caracteres codificados em
hexadecimal, precedidos por um sinal de "%".
Num formulário, cada item de entrada de dados possui um atributo name, ao qual associamos o nome
do campo. Quando o utilizador introduz dados, valores, num destes campos, esses dados são
associados ao nome do campo. Os pares nome=valor são formados pelo browser quando o utilizador
submete um formulário.
O utilizador comum não precisa ter a preocupação de criar um script CGI (que não é tarefa fácil, pois o
programa requer algum conhecimento de uma linguagem de programação), pois já existem vários "pré-
fabricados" disponíveis gratuitamente na Internet que processam as informações fornecidas nos
formulários de uma maneira transparente.
Para utilizá-los não precisa saber mais do que alguns novos comandos HTML. Os mais conhecidos na
Internet são o MailMerge, o CGIEmail, o AnyForm, o FormMail, entre outros.
Os dois primeiros precisam estar instalados no servidor do seu fornecedor, mas infelizmente nem todos
os fornecedores oferecem este tipo de facilidade aos seus utilizadores. O AnyForm permite que o
utilizador fique totalmente independente do seu fornecedor, pois tudo está instalado numa máquina em
alguma parte do mundo. Como estamos em rede e todas as máquinas podem comunicar, o local onde
os dados estão a ser tratados não faz tanta diferença.
Exemplo completo
Considere o FORM abaixo:
<FORM METHOD=POST>
Login: <INPUT TYPE="text" NAME="login" SIZE="15">
<INPUT TYPE="submit" VALUE="Enviar">
</FORM>
http://alguma.máquina/cgi-bin/regista.pl?login=guest
O servidor ao receber um URL com uma query-string, chama o programa cgi identificado na 1ª parte do
URL (antes do '?') e guarda a parte depois do '?' na variável de ambiente QUERY_STRING. Supondo
que o utilizador digitou "guest" no campo login, quando o botão submit é clicado, o browser envia, ao
servidor, um pedido do tipo:
O pedido GET identifica o ficheiro a enviar (cgi-bin/regista.pl). Desde que o servidor esteja configurado
para reconhecer todos os ficheiros no directório cgi-bin como sendo um programa cgi, executa o
programa em vez de enviar o documento directamente ao browser, além disso coloca a
string login='guest' na variável de ambiente QUERY_STRING.
HTTP/1.0 identifica o tipo de protocolo usado.
As aplicações CGI podem retornar praticamente quaisquer tipo de documentos virtuais, desde que o
cliente os consiga gerir apropriadamente, por essa razão o pedido do cliente também passa o formato
de dados que ele pode aceitar (www/source, text/html, image.gif), sendo essa informação guardada na
variável de ambiente HTTP_ACCEPT e o programa CGI analisa essa variável para assegurar que
retorna um ficheiro num formato que o browser pode gerir. Este pedido identifica um cliente Lynx e
envia informação do user. Toda esta informação é tornada disponível para o programa CGI, juntamente
com informação adicional do servidor.
O programador de CGI's não consegue controlar por que método o programa vai ser chamado. Assim
os scripts são geralmente escritos para suportar ambos os métodos.
#! /usr/local/bin/tclsh
set request_method $env(REQUEST_METHOD)
if {$request_method =="GET"}{
set form_info $env(QUERY_STRING)
} else {
set size_of_form_information $env(CONTENT_LENGTH)
set form_info [read stdin $size_of_form_information]
}
A 1ª parte é um cabeçalho HTTP completo ou parcial, que no mínimo descreve o formato dos
dados retornados (exemplo html, plain, text, gif, etc) e uma linha em branco, que significa o fim
do cabeçalho.
A 2ª parte é o corpo, que contem os dados de acordo com o tipo de formato considerado no
cabeçalho. O corpo não é modificado ou interpretado pelo servidor.
Um programa CGI pode escolher entre enviar os dados recém-criados directamente para o cliente ou
enviá-los indirectamente através do servidor.
Cabeçalho da mensagem
HTTP/1.0 200 OK
Date: Thursday, 22-February-96 08:28:00 GMT/
Server:NCSA/1.4.2
MIME-version: 1.0
Content-type: text/html
Content-length: 2000
Corpo da mensagem
<HTML>
<HEAD><TITLE> Welcome to </TITLE></HEAD>
<BODY>
<H1>Welcome</H1>
...
</BODY>
</HTML>
Como costuma ser o caso, o output é enviado ao servidor como sendo um conjunto de dados
(cabeçalho HTTP muito parcial) e o servidor é depois responsável por completar a informação do
cabeçalho e de usar o protocolo HTTP para transferir os dados ao cliente.
Cabeçalho da mensagem
Content-type: text/html
Corpo da mensagem
<HTML>
<HEAD><TITLE> Welcome to FEUP HOMEPAGE</TITLE>
</HEAD>
<BODY>
<H1>Welcome!</H1>
...
</BODY>
</HTML>
Explicação do exemplo
A seguir é apresentado o código da cgi, que constrói o resultado que possivelmente viu se clicou no
botão "Enviar" do formulário apresentado na introdução deste módulo. O objectivo deste programa CGI,
é listar os parâmetros que o utilizador introduziu no formulário, está escrito em linguagem c e chama-se
lepar.c.
No que diz respeito a permissões dos ficheiros e directórios, este ficheiro tem permissões rwx--x--x (em
Unix: chmod 711 lepar.c) e foi colocado num directório public-html/cgi-bin, que tem permissões rwxr-xr-
x.
entrada[i]='\0';
printf( "<li>%s</ul>", entrada );
}
1. Introdução
CGI (Common Gateway Interface) é um serviço server-based o qual adiciona
funcionalidade extra a uma página. Esta funcionalidade é fornecida por um 'pequeno'
programa ou 'script' que é executado no servidor onde a página web fica. Estes
programas podem ser feitos em diversas linguagens como Perl, PHP, C, Shell Script,
etc.
Como gosto muito de Shell Script resolvi escrever um tutorial básico sobre como
fazer CGI em Shell. Isto tem várias vantagens, pois você pode utilizar vários
comandos do UNIX para ajudar a construir seu script, por exemplo sed, awk, cut,
grep, cat, echo, bc, etc. além dos recursos do próprio shell.
Ok, como este tutorial não vai ser muito grande, vamos direto ao ponto.
2. Configuração
Como configurar o servidor web Apache para executar CGI ?
CGI é um módulo do Apache, assim ele precisa ser carregado. A maioria das
distribuições já vem com o seu httpd.conf configurado com suporte ao módulo do
CGI (mod_cgi), bastando apenas iniciar o Apache. Para se certificar procure e, se for
o caso, descomente a seguinte linha no seu httpd.conf:
LoadModule cgi_module /usr/lib/apache/1.3/mod_cgi.so
PS: Note que a terceira coluna pode variar dependendo da versão do Apache e da
distribuição que você está usando.
1. ScriptAlias
2. fora do ScriptAlias
esta diretiva acima permite a execução de CGIs, mas você ainda precisa avisar
o Apache que tipo de arquivos são estes CGIs. Procure por uma linha igual ou
semelhante a esta no seu httpd.conf e descomente.
AddHandler cgi-script .cgi .sh .pl
OBS: se você colocar um index.cgi em algum diretório e quiser que por default o
Apache execute-o, não se esqueça de adicionar esta extensão no
seu DirectoryIndex.
<IfModule mod_dir.c>
DirectoryIndex index.html index.htm index.shtml index.cgi
</IfModule>
O Apache irá procurar pelo index.cgi seguindo a ordem dos argumentos, ou seja, o
index.cgi será a última opção que ele irá procurar no diretório.
você não deve colocar seus scripts no document root do Apache, porque
alguém pode pegar seus scripts, analisá-los procurando furos de segurança,
etc. Além do mais, o código do script não é o que você quer mostrar :) Então
mantenha-os em /usr/lib/cgi-bin ou algum outro diretório fora do document
root.
o script precisa ser um executável, não se esqueça de dar um chmod nele.
Ah, certifique que o script tem permissão de execução para o usuário que o
Apache está rodando.
3. Diversão
3.1. Iniciando
Assumimos que você já tem o seu servidor web configurado para executar CGI.
Agora é hora da diversão :-)
O básico que você precisa saber é que toda a saída padrão (stdout) do seu script vai
ser enviada para o browser.
O exemplo mais simples é você imprimir algo na tela. Vamos ao nosso exemplo:
================ simples.cgi ====================
#!/bin/bash
Ok, então percebemos que toda saída do nosso script é enviada para o browser, toda
a saída mesmo. Por exemplo, podemos utilizar a saída de um comando:
================ saida_cmd.cgi ==================
#!/bin/bash
REMOTE_ADDR IP do cliente
SERVER_ADDR IP do servidor
"
set
=================================================
Então para garantir procure sempre especificar o cabeçalho!! Para enviarmos tags
html e o browser interpretá-las, temos que utilizar um cabeçalho diferente. Este
cabeçalho é content-type: text/html Então vamos enviar tags html para deixar nossa
saída mais bonita:
================ sobre.cgi ======================
#!/bin/bash
echo "<h4>uptime</h4>"
echo "<pre>$(uptime)</pre>"
echo "<h4>uname</h4>"
echo "<pre>$(uname -a)</pre>"
echo "<h4>/proc/cpuinfo</h4>"
echo "<pre>$(cat /proc/cpuinfo)</pre>"
echo "
</body>
</html>
"
=================================================
ARQ="/tmp/page.hits"
echo "
<h1>Esta página já foi visualizada: $n vezes</h1>
<br>
</body>
</html>"
=================================================
Com o que sabemos até agora, dá (ops!) para fazer vários script legais, fazer
monitoramento do sistema, de sua rede..., tudo via web.
Agora que já aprendemos o básico, queremos interagir com o usuário. Neste ponto
nós temos um detalhe, pois o nosso script não pode usar a entrada padrão (stdin) para
receber dados e não podemos fazer um read em um CGI, pois como nós leriamos o
que o usuário digitasse no teclado? :)
Usando o método GET o nosso script deve pegar os inputs do usuário via uma
variável de ambiente, no caso a $QUERY_STRING. Tudo o que vier após o
caractere '?' na URL será colocado naquela variável. Os campos de input do FORM
são separados pelo caractere '&' e possuem a seguinte construção: name=value.
Vamos a um exemplo de um CGI que recebe como entrada um host que será
executado no ping.
================ ping_get.cgi ===================
#!/bin/bash
echo "</body>"
echo "</html>"
=================================================
No método POST as opções do FORM não são passadas pela URL, elas são
passadas internamente do servidor para o CGI. Deste modo, com este método o
nosso script deve ler as opções pela entrada padrão. Vamos a um exemplo em que o
CGI envia um mail para alguém através da página. Neste caso, um pouco mais
complexo, temos dois arquivos. O primeiro um .html puro, onde construimos o
FORM, e colocamos como opção 'action' o nosso script. A opção action passada no
FORM, indica qual script será chamado para tratar os dados passados pelo FORM.
================ contato.html ===================
<html> <head> <title> CGI script </title> </head>
<body>
<form method="post" action="/cgi-bin/contato.cgi">
Nome:<br>
<input type="text" name="name" maxlength="50" size="30">
<p>
E-mail:<br>
<input type="text" name="address" maxlength="50" size="30">
<p>
Selecione o assunto:
<select name="subject">
<option value="none">-------------------------
<option value="venda">Informações sobre produto
<option value="suporte">Suporte técnico
<option value="web">Problema no site
</select>
<p>
Sua mensagem:<br>
<textarea name="message" wrap="physical" rows="6" cols="50">
</textarea>
<p>
<input type="submit" value="Enviar Mensagem">
<input type="reset" value="Limpar">
</form>
</body>
</html>
=================================================
Agora o nosso script lê da entrada padrão e faz o tratamento necessário. Note que
para enviar o mail, podemos utilizar qualquer programa de mail, por exemplo o mail,
sendmail...
================ contato.cgi ====================
#!/bin/bash
meu_mail="user@localhost.com.br"
echo "<br>
<br><b>Nome:</b> $nome
<br><b>mail:</b> $mail
<br><b>Subject:</b> $subj
<br><b>Message:</b> $text
<br>"
echo "</body>"
echo "</html>"
=================================================
Quando o seu servidor web envia os dados do FORM para o seu CGI, ele faz um
encode dos dados recebidos. Caracteres alfanumérico são enviados normalmente,
espaços são convertidos para o sinal de mais (+), outros caracteres como tab, aspas
são convertidos para %HH, onde HH são dois dígitos hexadecimais representando o
código ASCII do caractere. Este processo é chamado de URL encoding.
Tabela para os caracteres mais comuns:
\t (tab) %09
\n (return) %0A
/ %2F
~ %7E
: %3A
; %3B
@ %40
& %26
http://www.shelldorado.com/scripts/cmds/urlencode
http://www.shelldorado.com/scripts/cmds/urldecode
3.4. Upload
Agora que já sabemos utilizar os métodos GET e POST vamos a um exemplo um
pouco diferente. Vamos supor que precisamos fazer um CGI que permita o usuário
fazer um upload de um arquivo para o servidor. Aqui utilizamos um FORM um
pouco diferente. Falamos para o FORM utilizar um tipo de codificação diferente, no
caso enctype="multipart/form-data". Criamos um HTML normalmente e como
opção do action colocamos o nosso script.
================ upload.html ====================
<html>
<body>
<form enctype="multipart/form-data" action="/cgi-bin/upload.cgi"
method="post">
Enviar arquivo: <input name="userfile" size="30" type="file">
<BR><BR>
<input type="submit" value="Envia" name="Envia">
</form>
</body>
</html>
=================================================
O nosso script é quase igual a um POST normal. A principal diferença é que o input
para o script não vem em uma única linha, e sim em várias. Quem faz isto é
o enctype="multipart/form-data". Vem inclusive o conteúdo do arquivo via POST!!
Então pegamos tudo da entrada padrão. Note que junto com o input vem outras
cositas mas =8) Vamos a um exemplo:
================ upload.cgi =====================
#!/bin/bash
#echo
#echo "boundary = $boundary"
echo "</pre></body></html>"
=================================================
3.5. CheckBox
Para relaxar um exemplo mais simples, vamos fazer um CheckBox. Primeiro criamos
uma página HTML com o FORM para checkbox normalmente. Vamos utilizar o
método POST no exemplo.
================ checkbox.html ==================
<html><head><title>distro</title></head>
<body>
</body>
</html>
=================================================
Pegamos os inputs do FORM na entrada padrão. Eles são separados por &. Todas as
opções que o usuário selecionar virão no POST. Ah, não se esqueça, name=value.
Um exemplo de input que recereberemos:
debian=1&conectiva=1
Assim, sabemos que o usuário escolheu estas duas opções. Basta fazer o script.
================ checkbox.cgi ===================
#!/bin/bash
</body>
</html>
=================================================
O que será enviado pelo POST é o input escolhido. Como é Radio Buttons, somente
uma opção é aceita, assim temos o input: name=value, onde name é a variável distro
e value é a opção escolhida pelo usuário. Um exemplo é: distro=Debian
================ radiobuttons.cgi ===============
#!/bin/bash
echo "Sua distro predileta eh: <b>$(echo $VAR | cut -d= -f2)</b>"
=================================================
Para arrumar este problema, vamos aproveitar e incluir um novo tópico aqui.
SSI são diretivas que colocamos em uma página HTML pura para que o servidor
avalie quando a página for acessada. Assim podemos adiconar conteúdo dinâmico a
página sem precisarmos escrever toda ela em CGI. Para isto basta configurar o seu
Apache corretamente. Quem fornece esta opção é o módulo includes (mod_include),
simplesmente descomentamos a linha que carrega este módulo:
LoadModule includes_module /usr/lib/apache/1.3/mod_include.so
http://httpd.apache.org/docs/howto/ssi.html
http://httpd.apache.org/docs/mod/mod_include.html
3.7.2. Contador
while :;do
for URL in $(cat < $PIPE);do
FILE="$DIR/$(echo $URL | sed 's,.*/,,')"
# quando rodar como daemon comente a proxima linha
echo "arquivo = $FILE"
Este script será um daemon, isto é, rodará em background. Quando uma página
sofrer um acesso, ela escreverá a sua URL no arquivo de pipe. Para testar, execute
este comando:
echo "teste_pagina.html" > /tmp/pipe_contador
PS: assim que tiver tempo vou tentar explicar melhor este tópico.
3.8. Segurança
3.8.1. Introdução e Configuração
Este é um tópico importante quando falamos sobre CGI, principalmente os que têm
algum tipo de interação com o usuário. Mas para aumentar um pouco a segurança de
nossos CGIs podemos utilizar a opção AccessFileName do Apache. Ela nos permite
especificar quais usuário terão acesso a um determinado diretório. Por exemplo,
podemos especificar quais usuários terão acesso aos scripts
em http://localhost/cgi-bin/controle/
Esta opção define para o Apache o nome do arquivo que terá as informações sobre o
controle de acesso de cada diretório. Procure e, se for o caso, descomente as
seguintes linhas para não deixar nenhum usuário baixar nossos arquivos de controle
de acesso e de usuários e senhas.
<Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
Agora temos o nosso Apache configurado, vamos configurar o nosso .htaccess. Este
arquivo tem a seguinte estrutura:
AuthName "Acesso Restrito"
AuthType Basic
AuthUserFile /PATH/TO/.htpasswd
require valid-user
Onde:
AuthUserFile o PATH para o arquivo que contém a lista de user e senha válido
require valid-user
Calma, isto que vimos é Apache puro. Mas agora vem o pulo do gato :) Vamos
continuar nosso exemplo. Crie o seguinte arquivo e coloque em /usr/lib/cgi-
bin/controle
================ set.cgi =====================
#!/bin/bash
echo "
<input type=radio name=op value=w> Ver quem esta logado<br>
<input type=radio name=op value=df> Ver uso do disco<br>
<input type=submit value=Enviar>
</form>
</body>
</html>"
=================================================
case "$op"
in
"halt" )
echo "desligando a maquina ..."
;;
"reboot" )
echo "reinicializando a maquina ..."
;;
"w" )
echo "Usuários logado:"
echo "<pre>$(who)</pre>"
;;
"df" )
echo "Disco"
echo "<pre>$(df -Th)</pre>"
;;
* )
echo "opcao invalida</body></html>"
exit
;;
esac
echo "</body></html>"
=================================================
Note que estamos indo direto a segunda página controle_post.cgi. O lynx pra quem
não sabe é um browser modo texto. No exemplo, ele está enviando os dados que
recebeu da entrada padrão via o método POST para aquela URL.
case "$op"
in
"halt" )
[ "$REMOTE_USER" != "gerente" ] && { echo "opcao
invalida"
set >> "/tmp/CGI_halt_$REMOTE_ADDR"; echo
"</body></html>"; exit; }
echo "desligando a maquina ..."
;;
"reboot" )
[ "$REMOTE_USER" != "gerente" ] && { echo "opcao
invalida"
set >> "/tmp/CGI_reboot_$REMOTE_ADDR"; echo
"</body></html>"; exit; }
echo "reinicializando a maquina ..."
;;
"w" )
echo "Usuários logado:"
echo "<pre>$(who)</pre>"
;;
"df" )
echo "Disco"
echo "<pre>$(df -Th)</pre>"
;;
* )
echo "opcao invalida</body></html>"
exit
;;
esac
echo "</body></html>"
=================================================
Moral da história: quando utilizar interação com o usuário tem que testar tudo!!!
teste, teste, teste. Verifique as opcões, variáveis, etc.
4. LAN +_+
Exemplo prático. Vamos monitorar os host de nossa LAN. Saber quais estão ativos,
quais não respondem e informações sobre um determinado host. Este fonte é apenas
uma estrutura básica, mas server para se ter uma idéia do quão poderoso pode ficar
um CGI em Shell. Crie os seguintes arquivos em /usr/lib/cgi-bin/lan
================ lan.cgi ========================
#!/bin/bash
echo "
<body bgcolor=white>
<div align=right>Usuário: <b>$REMOTE_USER</b></div>
<center><h2>Máquinas da LAN</h2>
<form method=\"post\" action=\"lan_info.cgi\">
<table widthborder=0 cellpadding=2>"
if [ $? -eq 0 ];then
echo "<td align=\"center\"> <img
src=\"/icons/penguin_on.jpg\" alt=\"$host OK\" border=0></a></td>"
echo "<td><input type=radio name=host
value=\"$host\"><br>$host</td>"
elif [ $? -eq 1 ] ;then
echo "<td align=\"center\"> <img
src=\"/icons/penguin_off.jpg\" alt=\"Sem reposta da $host\"
border=0></a></td>"
echo "<td><br>$host</td>"
elif [ $? -eq 2 ] ;then
echo "<td align=\"center\"> <img
src=\"/icons/penguin_off.jpg\" alt=\"$host nao existe\" border=0></a></td>"
echo "<td><br>$host</td>"
fi
echo "
</table><br>
</form>
</center>
</body></html>"
=================================================
PS: não se esqueça que para executar o rsh, ele precisa estar configurado e não pedir
senha. Para testar rsh host ls. O usuário default do Apache não tem shell, assim você
precisa rodá-lo com um outro usuário.
================ lan_info.cgi ===================
#!/bin/bash
<body bgcolor=white>
<div align=right>Usuário: <b>$REMOTE_USER</b></div>"
VAR=$(sed -n '1p')
host=$(echo "$VAR" | sed 's/^host=\(.*\)\&.*$/\1/')
botao=$(echo "$VAR" | cut -d= -f3)
for i in a b c d; do
TEMP=$(rsh "$host" "test -L \"/proc/ide/hd$i\" && echo sim")
[ "$TEMP" = "sim" ] && \
echo -n "hd$i : $(rsh "$host" cat
"/proc/ide/hd$i/{media,model}" | sed 'N;s/\n/ /')<br>"
done
Você precisa baixar estas duas imagens utilizadas para mostrar se os hosts estão
respondendo ou não.
5. Resumão
POST & GET
Bom, com este texto espero ter dado uma visão geral de como funciona CGI em
Shell Script. Assim que tiver tempo vou procurar incrementar o texto adicionando
novos exemplo, explicando mais os conceitos...
Silvano B. Dias
Aurélio Marinho Jargas
Vinícius Della Líbera
Julio Cezar Neves