É hora de colocar em prática os nossos conhecimentos de funções e módulos para criar nosso primeiro programa para a Internet: o Calendário Dinâmico. Uma vez instalado em um servidor web, ele exibirá o calendário do mês atual com o dia de hoje assinalado. Ao final desse capítulo você terá construído seus primeiros programas CGI em linguagem Python. Mas para chegar lá, é preciso entender o funcionamento de um CGI, e conhecer como se dá a operação básica de um servidor HTTP. Quem é quem do HTTP
A Web é construída a partir de duas tecnologias fundamentais: a linguagem HTML e o protocolo HTTP. HTML, ou Hypertext Markup Language é a codificação usada para criar as páginas da Web. Este não é o assunto deste curso, mas vamos usar um pouco de HTML nos exemplos desse capítulo.
O segundo pilar da Web é o HTTP, ou Hypertext Transport Protocol - protocolo de transporte de hipertexto. Esse é o conjunto de comandos e regras que define como deve ser a comunicação entre um browser (como o Internet Explorer ou o Mozilla) e um servidor HTTP (como o Apache ou o Interner Information Server). A expressão “servidor HTTP” pode significar duas coisas: o software que serve páginas via HTTP, ou o computador onde esse software está instalado. No mundo Unix, softwares servidores são chamados de “daemons”, e a sigla HTTPd descreve um “HTTP daemon” genérico. Essa é a sigla que vamos usar para diferenciar o software do hardware.
A relação entre um browser e um HTTPd é descrita pelos computólogos como “cliente-servidor”. Isso significa que a interação entre esses dois softwares sempre parte do browser, que é o cliente. O servidor não tem nenhuma iniciativa, limitando-se a responder aos comandos enviados pelo cliente.
Quando você digita uma URL como http://ramalho.pro.br/aprendaprog/index.html, o seu browser localiza e conecta-se ao servidor ramalho.pro.br e envia-lhe o comando GET /aprendaprog/index.html. O servidor então lê o arquivo index.html da pasta aprendaprog, transmite seu conteúdo para o cliente e encerra a conexão. Esses são os passos básicos de qualquer interação de um browser com um HTTPd: conexão, solicitação, resposta e desconexão.
No exemplo que acabamos de ver, index.html é o que chamamos de uma página estática. A resposta do servidor consiste apenas em enviar uma cópia do documento para o cliente. Sites que incluem transações (como lojas virtuais), interatividade (como chats), ou atualizações muito freqüentes (como este) utilizam páginas dinâmicas. Neste caso, ao receber a URL http://www.magnet.com.br/ index_html, nosso servidor HTTPd Apache passa a solicitação para o aplicativo Zope, instalado no servidor. O Zope monta imediatamente a página index_html listando as notícias mais recentes de nosso banco de dados, a hora atual e outros elementos. A página recém montada então é passada para o Apache, que finalmente a transmite para o seu navegador.
O Zope é apenas uma das tecnologias de páginas dinâmicas que existem hoje. O ASP da Microsoft, o !ColdFusion da Macromedia e o software livre PHP são outros sistemas dinâmicos de montagem de páginas. Mas o mecanismo mais antigo, e também o mais simples de entender e de configurar, é o velho e bom CGI - ou Common Gateway Interface, um protocolo básico para interação entre um HTTPd e um programa gerador de páginas dinâmicas. É com ele que nos vamos trabalhar a partir de agora.
Para desenvolver aplicativos CGI é importante ter um bom ambiente de testes. O ideal é ter acesso a um HTTPd só para você na fase de desenvolvimento, para maior agilidade na depuração, e não correr o risco de comprometer o funcionamento de um servidor público com bugs nos seus CGIs em construção.
Pode ser que o seu micro já possua um servidor HTTP. A Microsoft inclui o Personal Web Server ou o IIS em diferentes versões do Windows. Você pode tentar usar um desses HTTPd para fazer os exemplos, mas sugerimos fortemente que você vá até o http://www.apache.org baixe o Apache, que não custa nada (é open source), roda em qualquer plataforma Win32 ou Unix, é fácil de instalar e é tão robusto e versátil que é o HTTPd mais usado em todo mundo, alem de ser o favorito disparado entre os melhores e maiores sites da Web. Vale a pena conhecê-lo, e o download tem apenas 3 MB.
No Windows, o Apache vem com um instalador bem amigável. Nossa única recomendação é instalar diretamente em um diretório como c:apache e não no famoso c:Arquivos de Programas. Isso porque os espaços em nomes de diretórios às vezes causam problemas na execução de programas originários do Unix como Python e o próprio Apache.
Uma vez terminada a instalação, você deve rodar o servidor, acionando o programa “Start Apache” que foi instalado em Iniciar > Programas > Apache Web Server. Isso faz abrir uma janela DOS com uma mensagem como “Apache/1.3.9 (Win32) running...”. Não feche esta janela, pois isso encerrará a execução do servidor. Agora você pode ver se está tudo certo digitando essa URL mágica em seu browser: http://127.0.0.1/. Se a instalação foi bem sucedida, você verá uma página com o texto: “It Worked! The Apache Web Server is Installed on this Web Site!” (Funcionou! O servidor Apache está instalado neste Web Site!). (Figura 1).
Vale a pena saber que o endereço 127.0.0.1 tem um significado especial. Os criadores da Internet reservaram esse número IP para o “loopback”, ou seja, testes de conexão de uma máquina com ela mesma. Em outras palavras, o endereço 127.0.0.1 sempre se refere à maquina onde você está, que é conhecida também pelo nome “localhost”. Se o seu micro estiver bem configurado, a URL http://localhost/ deve ter o mesmo efeito. Caso contrário, utilize o número IP e vamos em frente.
Chegamos ao grande momento. Seguindo a tradição milenar, vamos começar fazendo um CGI em Python que produz uma página com as palavras “Olá, Mundo!”. O programa completo você vê na listagem abaixo:
1 2 3 4 5 6 7 | #!/python/python
print 'Content-type: text/html'
print
print '<HTML><BODY>'
print '<H1>Olá, Mundo!</H1>'
print '</BODY></HTML>'
|
Antes de digitar este exemplo, é bom destacar dois aspectos essenciais. Primeiramente, o comentário da linha 1 é importante. O CGI não vai funcionar sem ele. Ao executar um script CGI, o Apache procura na primeira linha um comentário especial marcado pelos caracteres ‘#!’. Os sinais ‘#!’ devem estar encostados na margem esquerda da página, e o restante dessa linha deve conter o caminho até o programa executável do interpretador que rodará o script. Note que o caminho pode ser especificado usando a barra ‘/’ do Unix, em vez da contra-barra ‘’ preferida pelo Windows.
Em meu computador, o Python está instalado em uma pasta chamada “python” localizada no mesmo drive onde está o Apache (D:, no meu caso). Se o seu Python está instalado em outro lugar, você precisará alterar a linha 1. Em caso de dificuldades, nossa sugestão é que você desinstale o interpretador e o reinstale em uma pasta “python” diretamente na raiz do mesmo disco onde você acabou de instalar o Apache.
Outro detalhe importante são os print das linhas 3 e 4. Sua função não é meramente decorativa. O comando print ‘Content-type: text/html’ produz a parte obrigatória do cabeçalho da página, exigida pelo protocolo CGI. Este cabeçalho define o tipo do documento a ser transmitido de acordo com um esquema de classificação chamado “MIME”. O “text/html” é o “MIME type” padrão de documentos HTML. Um texto ASCII puro teria o MIME type “text/plain” e um arquivo de foto JPEG seria “image/jpeg”. O print da linha 4 gera uma linha em branco, que marca o fim do cabeçalho. Se uma dessas duas linhas não for digitada corretamente, o CGI não funcionará.
O restante da listagem apenas produz o código HTML de uma página muito simples. Os comandos marcados pelos sinais < e > são os chamados tags, ou marcações, da linguagem HTML. A marcação <H1>Manchete</H1>, por exemplo, define que uma manchete de nível 1, que será exibida pelo navegador como um texto em letras grandes.
O programinha de exemplo da seção anterior deverá ser salvo com o nome ola.py no diretório cgi-bin dentro da pasta do Apache. Este diretório é criado automaticamente pelo instalador do Apache no Windows, mas deve estar vazio inicialmente. Coloque o ola.py ali dentro e faça o grande teste: digite http:// 127.0.0.1/cgi-bin/ola.py em seu browser. Das duas, uma: ou você viu a página “Olá, Mundo!” e está feliz com seu primeiro CGI, ou ficou deprimido por encontrar uma mensagem de “Internal Server Error”. Neste caso, saiba que você está em boa companhia: todo programador de CGI já se deparou com esta mensagem. Os que dizem que nunca a viram estão mentindo. Mesmo que seu script tenha funcionado, é proveitoso entender as causas de um “Internal Server Error” para saber como depurá-lo.
O “Internal Server Error” ocorre quando o script CGI não gera um cabeçalho mínimo, formado por uma linha de Content-type e uma linha em branco. É o que o nosso ola.py deveria fazer nas linhas 3 e 4. Vejamos passo a passo como diagnosticar a causa do problema.
Abra uma janela do DOS e digite:
X:\> c: (ou d:)
O passo acima não é necessário se você já está no disco certo:
X:\> cd \apache\cgi-bin
X:\> python ola.py
Neste momento, três coisas podem acontecer:
- O script funciona perfeitamente, exibindo o cabeçalho, uma linha em branco, e o HTML da página - pule para o passo (b).
- O DOS responde “Comando ou nome de arquivo inválido” - leia o passo (c).
- O interpretador Python exibe um traceback e uma mensagem de erro qualquer - vá até o passo (d).
Neste caso, existem quatro causas possíveis:
$ chmod a+x ola.py
Se você usa outro Unix, experimente:
$ chmod 755 ola.py
Uma vez marcado como executável o script poderá ser invocado diretamente pelo nome, sem necessidade de mencionar o interpretador, assim:
$ ./ola.py
Se este teste funcionou, tente acionar o script novamente pelo browser, porque um shell do Unix também utiliza o comentário #! da linha 1 para localizar o interpretador. Se isto não deu certo, volte ao item 2a acima. Se o teste funcionou mas o programa exibe um traceback, vá até o passo (d).
Todo
Revisar todas as referências cruzadas tipo “vá até o passo x”
Verifique se o interpretador Python (arquivo python.exe no DOS) está instalado corretamente e em local acessível. Se ele foi instalado em uma pasta chamada c:python, o seguinte comando deve acionar o seu CGI:
X:\> c:\python\python ola.py
O que fazer então:
Se ao rodar o script a partir do prompt você está vendo um traceback do interpretador Python, o problema está mesmo dentro do seu programa. Quando ocorre um erro de sintaxe (SyntaxError) o interpretador apenas leu, mas não chegou a executar nenhuma linha do seu script. Assim, o famoso cabeçalho “Content-type: ...” e a linha em branco não são enviados para o servidor, e o traceback que o ajudaria a detectar o problema não chega ao seu browser, mas vai para um arquivo onde o Apache registra mensagens de erro. Este arquivo chama-se error.log e fica em /apache/logs/. Você pode inspecioná-lo com qualquer editor de texto. Outras vezes, o erro pode acontecer durante a execução e após o envio do cabeçalho. Neste caso, o traceback é perdido para sempre. É por isso que programadores de CGI experientes procuram testar exaustivamente seus scripts a partir da linha de comando antes de tentar acioná-lo pelo browser. Há tambem aguns truques que podem ser usados durante a depuração de um CGI para que as mensagens de erro sejam transmitidas para o browser. Em seguida veremos como.
Nosso primeiro exemplo de CGI foi bolado para ser simples, mas é também um tanto tolo. Não gera nenhuma informação variável; o mesmo efeito poderia ser obtido com uma página estática. A página dinâmica mais simples que conseguimos imaginar é uma que mostre a hora certa (de acordo com o relógio do servidor). Para fazer um CGI assim, é bom conhecermos duas funções do módulo time. Vamos ver o que elas fazem acionando o interpretador Python. Primeiro, temos que importar as duas funções de dentro do módulo:
>>> from time import time, localtime
Podemos invocar diretamente a função time():
>>> time()
953500536.8
Que número é esse? Como explicamos no final do capítulo passado, o Python, assim como muitos programas originários da plataforma Unix, marca o tempo contando o número de segundos desde 1 de janeiro de 1970. Isto quer dizer que haviam se passado 953 milhões, 500 mil e 536 segundos e 8 décimos desde 1/1/1970 quando eu digitei time() no IDLE do meu computador. Isto é muito interessante, mas como transformar segundos transcorridos na hora atual? É para isso que serve a função localtime():
>>> t = time()
>>> localtime(t)
(2000, 3, 19, 18, 33, 19, 6, 79, 0)
>>>
Agora nós associamos os segundos transcorridos à variável t, e em seguida usamos a função localtime para transformar os segundos em uma seqüência de 9 números que fornecem os seguintes dados:
1 2 3 4 5 | localtime(t)[0:3] # 2000, 3, 19 (ano, mês e dia)
localtime(t)[3:6] # 18, 33, 19 (hora, minutos e segundos)
localtime(t)[6] # 6 (dia da semana; 0 = segunda-feira; 6 = domingo)
localtime(t)[7] # 79 (número do dia no ano; de 1 a 366 em anos bissextos)
localtime(t)[8] # 0 (indicador de horário de verão; 0 = não; 1 = sim)
|
Esta função se chama localtime porque além de converter de segundos transcorridos para data e hora, ela o faz levando em conta o fuso horário configurado no sistema operacional, fornecendo portanto a hora local. Para saber a hora no meridiano de Greenwich, ou UTC no jargão moderno, usaríamos a função gmtime():
>>> from time import gmtime
>>> gmtime(t)
(2000, 3, 19, 21, 33, 19, 6, 79, 0)
>>>
Agora vamos combinar as novas funções para montar um CGI, hora.py, que mostre a hora local do servidor:
1 2 3 4 5 6 7 8 9 10 11 12 | # hora.py - CGI que exibe a hora local do servidor
from time import time, localtime
print 'Content-type: text/html'
print
h, m, s = localtime(time())[3:6]
print '<HTML><BODY>'
print '<H1>Hora: %02d:%02d:%02d</H1>' % (h, m, s)
print '<P>* de acordo com o relógio interno deste servidor</P>'
print '</BODY></HTML>'
|
Uma vez salvo no diretório cgi-bin, este script poderá ser acessado pela URL http:// 127.0.0.1/cgi-bin/hora.py. A página gerada conterá a hora, minutos e segundos do instante em que ela foi invocada. Qual o defeito do nosso relógio em CGI? Experimente e você verá.
É um pouco frustrante acessar uma página que mostra a hora certa, com precisão de segundos, mas fica parada no tempo (Figura 2). Para atualizar os segundos, você tem que acionar o comando de “reload” do seu browser (Exibir ¡ Atualizar ou [F5] no Internet Explorer; View ¡ Reload ou [Control][R] no Navigator). Nossa página parece um relógio quebrado, que só mostra a hora certa quanto chacoalhado.
O ideal seria que o servidor atualizasse a página que está no seu browser a cada segundo. Infelizmente, isso é impossível. Como já dissemos, o protocolo HTTP é do tipo cliente-servidor, e isto quer dizer que a iniciativa de toda interação fica do lado do cliente. Não há como o servidor por conta própria enviar uma nova página sem que ela seja antes solicitada pelo navegador. Esta é uma limitação importante do protocolo HTTP que você precisa ter em mente ao bolar seus programas CGI.
Os browsers modernos suportam uma uma solução parcial para este problema. Eles reconhecem um cabeçalho especial chamado Refresh, cuja presença em um documento serve para instruir o browser a solicitar novamente a página após algum tempo. O argumento do Refresh é um número de segundos que o navegador deve esperar para pedir a atualização. Logo veremos como isso funciona na prática.
Para usar o Refresh basta acrescentar uma linha ao cabeçalho da resposta gerado pelo nosso CGI hora.py. A nova versão, hora2.py ficará assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/python/python
# hora2.py - CGI que exibe continuamente hora local do servidor
from time import time, localtime
print 'Content-type: text/html'
print 'Refresh: 0.6'
print
h, m, s = localtime(time())[3:6]
print '<HTML><BODY>'
print '<H1>Hora: %02d:%02d:%02d</H1>' % (h, m, s)
print '<P>* de acordo com o relógio interno deste servidor</P>'
print '</BODY></HTML>'
|
A única novidade é a linha 7, onde acrescentamos “Refresh: 0.6” ao cabeçalho. Em vez de mandar o browser atualizar a página a cada 1 segundo, após alguns testes decidimos fazê-lo a cada 6 décimos de segundo. Fizemos assim porque quanto experimentamos com “Refresh: 1” a contagem freqüentemente pulava um segundo, por exemplo de 10:30:20 direto para 10:30:22. Isso não quer dizer que o relógio adiantava, porque a cada nova solicitação a hora certa estava sendo consultada pelo nosso CGI; mas como o tempo de espera somado ao tempo de solicitação e resposta era maior que 1 segundo, a exibição da hora sofria alguns sobressaltos.
Fazendo o refresh a cada 6 décimos, muitas vezes estamos atualizando a página duas vezes no mesmo segundo, o que é um desperdício de processamento. Mas pelo menos nos livramos da enervante perturbação na contagem. É claro que se o servidor estiver sobrecarregado, ele pode levar mais de um segundo para responder. Nesse caso, de nada adiantará se o browser fizer novas solicitações a cada 0.6 segundo.
Agora vamos juntar o que já sabemos sobre CGI com o módulo calendar que vimos no capítulo anterior para fazer um protótipo rápido do nosso Calendário Dinâmico. As passagens mais interessantes da listagem abaixo são comentados a seguir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #!/python/python
# calendin.py - calendário dinâmico - protótipo 1
print 'Content-type: text/html\n'
try:
from time import time, localtime
from calendar import monthcalendar
from string import join
ano, mes = localtime(time())[:2]
print '<HTML><TITLE>Calendário Dinâmico</TITLE>'
print '<BODY>'
print '<H1>Calendário do mês %02d/%04d</H1>' % (mes, ano)
print '<PRE>'
for semana in monthcalendar(ano, mes):
print join( map(str, semana),'\t' )
print '</PRE>'
except:
import sys
sys.stderr = sys.stdout
from traceback import print_exc
print '<HR><H3>Erro no CGI:</H3><PRE>'
print_exc()
print '</PRE>'
print '</BODY></HTML>'
|
O que fizemos, linha a linha:
Agora que colocamos o calendário básico para funcionar, está na hora de melhorar sua apresentação. Vamos deixar de lado o recurso preguiçoso do tag <PRE> e colocar os dias do mês dentro de uma tabela construída em HTML (Figura 3). Aproveitando outros recursos daquela linguagem, vamos também colorir os finais de semana e assinalar o dia de hoje. Você encontra o programa calendin2.py na listagem abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #!/python/python
# calendin2.py - calendário dinâmico - protótipo 2
print 'Content-type: text/html\n'
try:
from time import time, localtime
from calendar import monthcalendar
from string import join
ano, mes, hoje = localtime(time())[:3]
print '<HTML><TITLE>Calendário Dinâmico</TITLE>'
print '<BODY>'
print '<CENTER>'
print '<H1>Calendário de %02d/%04d</H1>' % (mes, ano)
print '<TABLE>'
print '<TR>'
for dia_sem in ['seg','ter','qua','qui','sex','sab','dom']:
if dia_sem in ['sab','dom']: bgcolor = 'green'
else: bgcolor = 'blue'
print '<TH WIDTH="45" BGCOLOR="%s">' % bgcolor
print '<H3>%s</H3></TH>' % dia_sem
print '</TR>'
for semana in monthcalendar(ano, mes):
print '<TR>'
num_dia_sem = 0
for dia in semana:
if dia == hoje:
bgcolor = 'pink'
elif num_dia_sem >= 5:
bgcolor = 'lightgreen'
else:
bgcolor = 'lightblue'
print '<TD ALIGN="RIGHT" BGCOLOR="%s">' % bgcolor
if dia != 0:
print '<H2>%2d</H2>' % dia
print '</TD>'
num_dia_sem = num_dia_sem + 1
print '</TR>'
print '</TABLE></CENTER>'
except:
import sys
from traceback import print_exc
sys.stderr = sys.stdout
print '<HR><H3>Erro no CGI:</H3><PRE>'
print_exc()
print '</PRE>'
print '</BODY></HTML>'
|
Principais novidades em relação à versão anterior:
Aqui termina nosso primeiro contato com programação aplicada à Web. Neste capítulo você instalou seu próprio servidor Apache, e implementou seus primeiros programas CGI. Os princípios que você está aprendendo aqui se aplicam a qualquer tecnologia de geração de páginas dinâmicas. Para construir os exemplos, lançamos mão de código HTML. Não é nosso objetivo aqui abordar esta outra linguagem, mas não podemos fazer coisas interessantes na Web sem conhecer um pouco dela. Vamos manter o uso de HTML em um nível bem elementar, e continuaremos explicando os tags mais importantes de cada exemplo, mas seu aproveitamento poderá ser melhor se você estudar por conta própria. O tutorial do Caique, que você encontra no site da [[http://www.magnet.com.br|Magnet]], é mais que suficiente para acompanhar o restante deste curso.
No próximo número, aperfeiçoaremos nosso calendário para torná-lo interativo: em vez de mostrar sempre o mês atual, vamos permitir que o usuário escolha um mês e um ano qualquer, e também navegue para frente e para trás de mês em mês. Isso nos levará a explorar o uso de URLs com argumentos e formulários em HTML. Até lá!
PS. A revista MAGNET deixou de ser publicada, então este tutorial não teve continuação...