Quando falamos em programação para Web, normalmente pensamos em linguagens como Perl, Java, PHP, mas raramente imaginamos C como uma linguagem para desenvolver aplicativos web. E esse chega a ser um fato curioso, visto os primeiros CGI's terem sido desenvolvidos em C.

Se a linguagem C serve para programação Web, por que não ouvimos falar de páginas web feitas nessa linguagem? Há diversos motivos, um deles é a facilidade de se programar em linguagens mais específicas para web como PHP ou mesmo linguagens com recursos como coletor de lixo (garbage collector) (dentre elas o Java), ao compararmos ao desenvolvimento usando C. Outro motivo é o desconhecimento, por parte de muitos programadores de Web, do que está por debaixo dos panos ao desenvolver um programa para web, contudo para desenvolver em C para Web precisamos estar atentos a isso.

Então, visto desse lado, há alguma vantagem em desenvolver em C as páginas de web? Sim, há muitas, mas as três mais importantes são:

  1. Desempenho – programas compilados em C costumam ser muito mais performáticos de que programas em linguagens interpretadas como PHP e Perl (obviamente se esses estiverem bem desenvolvidos);
  2. Consumo de memória – programas bem escritos em C consomem muito menos memória de que programas compilados e de que programas que precisem de uma máquina virtual para executá-los;
  3. Conhecimento do processo que existe ao fazer uma requisição web – mesmo se tu não utilizares CGI's em C no dia a dia, teu código tenderá obter melhora significativa de qualidade.

Quando desenvolvemos CGI’s em C, costumamos utilizar bibliotecas CGI para facilitar muitas das tarefas comuns, mas neste artigo trabalharemos sem usar as mesmas, assim a base de programação CGI em C será mais forte e, nos próximos artigos, quando aprendermos sobre uma biblioteca especializada para CGI em C++ (Wt), a compreensão do que está por detrás de cada método fará com que apreciemos mais seu uso.

Os requisitos para nosso desenvolvimento são um compilador C (os exemplos usarão o gcc, mas nada impede que uses outro compilador de tua preferência) e um servidor web como o Apache.

Se consegui convencer-te a continuar, então vamos a nosso primeiro programa, o tradicional “Alô, Mundo!” (ou “Hello, World!”, para quem prefere em inglês) – salve esse arquivo com o nome hello.c.


#include <stdio.h>

int main(int charc, char *charv[])
{
  printf("Content-type: text/plain\n\n");
  printf("Ola, Mundo!");

  return 0;
}

Se prestares atenção verás que não há nada diferente de um programa C tradicional. O primeiro comando printf contém o segredo para que este programa funcione como uma página CGI: toda página gerada por um CGI e enviada para o browser deve inicializar com uma linha indicando o tipo de documento que será enviado. Isso é feito com a cláusula “Content-type”, e o valor que atribuímos neste caso foi “text/plain”, ou seja, é um arquivo de texto simples apenas.

Logo após imprimir esta linha faz-se necessário seguir uma linha em branco, por isso temos duas vezes o caracter de nova linha no final dessa string (“\n\n”). Logo após, basta mandarmos imprimir nosso “Ola, Mundo!” e está feito.

Não há truques na compilação, é uma compilação padrão em C:


gcc -o hello hello.c

Teremos o nosso CGI compilado, agora somente falta colocar o mesmo na pasta CGI de seu servidor web. No meu caso é a pasta /var/www/cgi-bin/, mas em outros sistemas linux pode estar em diferentes pastas (no debian é na pasta /usr/lib/cgi-bin/). Para tanto, basta fazer uma cópia do nosso arquivo compilado para essa pasta e, supondo o servidor web estar ativo, podemos entrar em um browser e digitar:


http://<<endereco_ip>>/cgi-bin/hello </endereco_ip>

Onde <endereco_ip> deve ser substituído pelo IP de teu servidor (pode ser localhost se estiveres abrindo a página na mesma máquina na qual encontra-se o servidor web).

Nesse caso deve ver uma página onde estará escrito “Olá, Mundo!” apenas conforme imagem abaixo:

olá mundo

Vamos melhorar um pouco a aparência de nosso programa agora. O programa gerará uma página HTML desta vez, assim o “Content-type” tornar-se-á do tipo “text/html” no lugar de “text/plain”. Salve este programa com o nome hello2.c.


#include <stdio.h>

int main(int charc, char *charv[])
{
  printf("Content-type: text/html\n\n");
  printf("<html><head>\n");
  printf("<title>Ola, Mundo!</title>\n");
  printf("</head>");
  printf("<body><h1 align=center>Ola, Mundo!</h1>\n");
  printf("</body></html>");
  return 0;
}

Novamente, é preciso compilar:


gcc -o hello2 hello2.c

E copiar o programa compilado para a pasta cgi-bin do servidor web, exatamente como no programa anterior. Após a cópia, podemos digitar no browser:


http://<<endereco_ip>>/cgi-bin/hello2

E deverá aparecer algo semelhante a:

compilação

Até o momento não fizemos nada muito interativo nem muito surpreendente. Vamos então trabalhar com envio e recebimento de valores usando o método GET?

Vamos criar um formulário simples, no qual pediremos ao usuário sua idade e retornaremos a ele qual será a idade dele no próximo ano. Antes de começarmos, precisamos saber o que é passagem de parâmetros por método GET.

A passagem de parâmetros por páginas web pode ser feita por diversos métodos, sendo dois os mais comuns: GET e POST. Enviar valores por método GET é o mais simples, contudo também é o menos seguro, pois estes são enviados na própria URL da chamada. Existe um método de codificação para estas variáveis para que o script CGI consiga obter os nomes das variáveis e seus valores, cujas regras seguem:

  1. cada variável, inclusive seus valores, são separados entre si pelo símbolo & (e comercial)
  2. o nome e o valor de cada variável são separados pelo caractere = (igual)
  3. os espaços em branco existentes são substituídos pelo caractere + (mais)
  4. todos os caracteres ASCII estendidos, ou seja, com valores acima de 127, são substituídos por um caractere % seguido do valor hexadecimal do caractere
  5. os caracteres %, &, + e = também são convertidos em hexadecimal seguindo a mesma regra dos caracteres ASCII estendidos.

Um exemplo de URL para a qual passamos uma variável chamada “ano” com o valor “1981”:


http://localhost/cgi-bin/alo?ano=1981

As variáveis enviadas pelo método GET ficam em uma variável de ambiente chamada QUERY_STRING. Logo, para obtermos esse conteúdo teremos de ler essa variável de ambiente e trabalhar com a mesma.

Vamos ver como fazer com o programa que gera o formulário que mencionamos há poucos parágrafos (salve este programa com o nome idade.c):


#include <stdio.h>
#include <stdlib.h>

int main(int argv, char *argc[])
{
long idade;
/* variavel para armazenar o conteudo da variavel de ambiente QUERY_STRING   
   - o conteudo enviado pelo metodo GET */
char *dados;

/* obtendo as variaveis enviadas */
dados = getenv("QUERY_STRING");

/* verifica se tem conteudo enviado, caso nao tenha e porque                    
   o formulario ainda nao foi enviado */
if (strcmp(dados,"") == 0)
{
  printf("Content-type:text/html\n\n");
  printf("<html><head><title>Ola</title></head>\n");
  printf("<body>");
  printf("<form method=get action=idade>\n");
  printf("Qual a tua idade?<br>");
  printf("<input type=text maxlength=3 size=5 name=idade>");
  printf("<input type=submit value='continuar'>");
  printf("</form></body></html>");
}
/* neste caso o formulario foi enviado mas a variavel idade nao tem valor numerico */
else if(sscanf(dados,"idade=%ld",&idade) != 1)
{
  printf("Content-type:text/html\n\n");
  printf("Idade tem de ser numerica! Estas tentando enganar-me?");
}
/* neste caso o formulario foi enviado e tem valor numerico */
else
{
  printf("Content-type:text/html\n\n");
  printf("Tu tens %ld anos.<br> 
  Isso significa que no proximo ano teras %ld anos, estou certo?",idade,idade+1);
}

return 0;
}

Novamente, é preciso compilar:


  gcc -o idade idade.c

E copiar o programa compilado para a pasta cgi-bin do servidor web, exatamente como no programa anterior. Após a cópia, podemos digitar no browser:


http://<<endereco_ip>>/cgi-bin/idade
pasta cgi

Inserindo um valor numérico recebemos uma resposta semelhante a:

inserindo valor numérico

Inserindo valor não numérico recebemos uma resposta semelhante a:

inserindo valor não numérico

Como tínhamos um formulário simples, não houve muita preocupação com as variáveis recebidas, mas se prestarmos atenção o programa não trata todos os tipos de valores possíveis. Se o usuário passar um valor iniciado por números e terminado por valores alfabéticos ou outros caracteres não numéricos, ele ignorará todos os caracteres não numéricos e funcionará como se a idade mencionada tivesse sido numérica, o que neste caso não é problemático, mas em outro tipo de página poderia ser problemático.