Programa CGI en C que accesa una BD usando la libreria LPQ de Postgres

Ahora quiero mostrar como se usa la libreria LPQ para acceder a una base de datos de postgress. Yo le llamo la libreria LPQ a la libreria que nos permite establecer una conexion a una BD de Postgres desde un programa escrito en lenguaje C/C++.

los datos de conexion y la tabla a usar en el ejemplo son:
usuario: postgres
password: 12345
base de datos: prueba
tabla: alumnos

En la siguiente imagen se muestran los campos de la tabla alumnos:

El ejemplo que quiero mostrar esta compuesto de los archivos index.html, formularioAltas.html, formularioBajas.html, altaAlumnos.cgi, bajaAlumnos.cgi, mostrarAlumnos.cgi y a continuacion se muestra en la siguiente imagen como se relacionan entre si:

A continuacion se va a mostrar su codigo, se da una breve descripcion y se muestra una imagen de cada uno:

index.html
Este archivo es el principal y es una pagina web que esta localizada en la carpeta /usr/local/servidor_web/htdocs/lpq/index.html y se encarga de mostrar un menu con tres botones, uno para dar de alta un nuevo Alumno, el segundo para dar de baja un alumno y el tercero para consultar y mostrar el contenido de la tabla alumnos. Para no dar tantos detalles mejor muestro el codigo fuente de este archivo:

<!--		Instituto Tecnologico de Zacatepec
    Descripcion:   Indice de opciones del ejemplo que usa la libreria LPQ
    Author:     Gonzalo Silverio  gonzasilve@gmail.com
    Archivo:    index.html
-->
<HTML>
<HEAD>
   <TITLE> Ejemplo que usa la libreria LPQ </TITLE>
</HEAD>
<BODY bgcolor="#C9FF5C">
	<br>
    <h2 align="center">USO DE LA LIBRERIA LPQ DE POSTGRES</h2> <br>
    <TABLE width="80%" border="0" cellpadding="0" cellspacing="0" align="center">
    <TR>
        <TD align="center"><input type="button" name="alta" value="Dar de alta" onclick="location='formularioAltas.html'" > </TD>
        <TD align="center"><input type="button" name="baja" value="Baja de un alumno" onclick="location='http://localhost/lpq/formularioBajas.html'" ></TD>
        <TD align="center"><input type="button" name="ver" value="Ver tabla" onclick="location='http://localhost/cgi-bin/lpq/mostrarAlumnos.cgi'" ></TD>
    </TR>
    </TABLE>
</BODY>
</HTML>

Aca una imagen que muestra esta pagina en el navegador :

formularioAltas.html
Si el usuario elije el boton Dar de alta en la pagina principal, entonces se abrira este archivo que es una pagina web con un formulario. Esta pagina tiene como objetivo que el usuario rellene el formulario con datos de un nuevo alumno y mande estos datos a un programa CGI (altaAlumnos.cgi) al dar click en el boton Dar de alta!. Este archivo esta almacenado en /usr/local/servidor_web/htdocs/lpq. Bueno el contenido de este archivo es el siguiente:

<!--
		Instituto Tecnologico de Zacatepec
    Descripcion:
    Esta pagina web contiene un Formulario que se usara para enviar datos a un programa CGI
	 el cual los guardara en una tabla llamada alumnos de Postgres.
    Author:     Gonzalo Silverio   gonzasilve@gmail.com
    Archivo:    formularioAltas.html
-->
<html>
<head>
<title>Alta de un alumno</title>
</head>
<body bgcolor="#C9FF5C">
    <form name="form_altas" action="http://localhost/cgi-bin/lpq/altaAlumnos.cgi" method="GET">
        <table width="90%" border="1" align="center" bgcolor="#FFFFFF" >
            <tr>
                <td>
                    <table border="0" cellspacing="0" align="center" width="100%">
                <tr>
                    <td colspan="2" bgcolor="#6D6DFF"><h3 align="center">
                            <font color="white"><br><img src="logo_web.gif" alt="gonzasilve">
                                Alta de un nuevo alumno
                            </font></h3>
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019"><b>N.C:</b> </td><td><input type="text" name="nc" size="20" maxlength="10"> </td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019"><b>Nombre:</b> </td><td><input type="text" name="nombre" size="40" maxlength="255"> </td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019"><b>Apellidos:</b> </td><td><input type="text" name="apellidos" size="40" maxlength="255"> </td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019"><b>Direccion:</b> </td><td><textarea COLS="50" rows="3"  name="direccion" ></textarea></td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019">
                        <b>Estatura:</b> </td><td><input type="text" name="estatura" size="10" maxlength="10">
                        <font color="#a4a2a1">mts.</font>
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019">
                        <b>Peso:</b> </td><td><input type="text" name="peso" size="10" maxlength="10">
                        <font color="#a4a2a1">kgs.</font>
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019"><b>Fecha de ingreso:</b> </td><td>Dia
                        <select name="dia" size="1">
                            <option value="1">1</option>
                            <option value="2">2</option>
                            <option value="3">3</option>
                            <option value="4">4</option>
                            <option value="5">5</option>
                            <option value="6">6</option>
                            <option value="7">7</option>
                            <option value="8">8</option>
                            <option value="9">9</option>
                            <option value="10">10</option>
                            <option value="11">11</option>
                            <option value="12">12</option>
                            <option value="13">13</option>
                            <option value="14">14</option>
                            <option value="15">15</option>
                            <option value="16">16</option>
                            <option value="17">17</option>
                            <option value="18">18</option>
                            <option value="19">19</option>
                            <option value="20">20</option>
                            <option value="21">21</option>
                            <option value="22">22</option>
                            <option value="23">23</option>
                            <option value="24">24</option>
                            <option value="25">25</option>
                            <option value="26">26</option>
                            <option value="27">27</option>
                            <option value="28">28</option>
                            <option value="29">29</option>
                            <option value="30">30</option>
                            <option value="31">31</option>
                        </select>
                        <b>Mes</b>
                        <select name="mes" size="1">
                            <option value="01">Enero</option>
                            <option value="02">Febrero</option>
                            <option value="03">Marzo</option>
                            <option value="04">Abril</option>
                            <option value="05">Mayo</option>
                            <option value="06">Junio</option>
                            <option value="07">Julio</option>
                            <option value="08">Agosto</option>
                            <option value="09">Septiembre</option>
                            <option value="10">Octubre</option>
                            <option value="11">Noviembre</option>
                            <option value="12">Diciembre</option>
                        </select>
                        <b>a&ntilde;o</b>
                        <input type="text" size="4" maxlength="4" name="anio" value="">
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019"><b>Carrera:</b></td>
                    <td>
                        <select name="carrera" size="4">
                            <option value="ingSistemas">Ingenieria en Sistemas computacionales</option>
                            <option value="ingBioquimica">Ingenieria en Bioquimica</option>
                            <option value="ingCivil">Ingenieria Civil</option>
                            <option value="ingElectro">Ingenieria Electromecanica</option>
                            <option value="ingIndustrial">Ingenieria Industrial</option>
                            <option value="ingQuimica">Ingenieria en Quimica</option>
                            <option value="ingGestionEmp">Ingenieria en Gestion Empresarial</option>
                            <option value="maesQuimica">Maestr&iacute;a en Ciencias en Ingenier&iacute;a Qu&iacute;mica</option>
                            <option value="docPolimeroa">Doctorado en Ciencias en Polimeros</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td bgcolor="#ff9019"><b>Sexo:</b> </td><td>
                        <input type="radio" name="sexo" value="hombre">Masculino &nbsp;&nbsp;
                        <input type="radio" name="sexo" value="mujer">Femenino<br><br>
                    </td>
                </tr>
            </table>
            </td>
        </tr>
      </table>
      <br>
      <table border="0" width="80%" align="center">
            <tr>
                <td align="center">
                    <input type="submit" name="guardar" value="Dar de alta!">&nbsp;&nbsp;&nbsp;
                </td>
                <td align="center">
                    <input type="reset" name="limpiar" value="Limpiar">&nbsp;&nbsp;&nbsp;
                </td>
                <td align="center">
                    <input type="Button" name="cancelar" value="Cancelar alta" onClick="location='http://localhost/lpq/index.html'">
                </td>
            </tr>
       </table>
    </form>
</body>
</html>

Y aca se muestra una imagen con esta pagina en el navegador:

altaAlumnos.cgi
Este archivo es el que recibe los datos del formulario formularioAltas.html y a continuacion establece una conexion a la BD y ejecuta una operacion INSERT sobre la tabla alumnos. Este archivo esta almacenado en /usr/local/servidor_web/cgi-bin/lpq. A continuacion se muestra el codigo fuente en C de este programa CGI:


/*
		Instituto Tecnologico de Zacatepec
  Descripcion:	Programa que hacer un INSERT para dar de Alta a un nuevo 
					alumno en una tabla de alumnos de postgres
  Author:	Gonzalo Silverio  gonzasilve@gmail.com
  Archivo:	altasAlumnos.c
  Compilar con: 
		cc -c -I/usr/local/pgsql/include altaAlumnos.c
  Enlazar CGI con libreria LPQ con:
  		cc -o altaAlumnos.cgi altaAlumnos.o -L/usr/local/pgsql/lib -lpq
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "libpq-fe.h"

// Maximo 100 registros de alumnos
#define MAX 100

// Estrutura de datos que guarda los nombres de las variables CGI y sus valores de los formularios
struct 
{
  char nombre[128];
  char valor[128];
} elementos[MAX];

/* Estructura para guardar los datos del alumno */
struct datos
{
  char nc[128];
  char nombre[128];
  char apellidos[128];
  char direccion[128];
  double estatura;
  double peso;
  char fecha_ingreso[128];
  char carrera[128];
  char sexo[128];
} lista_alumnos;


void  guardar(void);

/* declaraciones de las funciones que se van a utilizar en el programa */
void splitword(char *out, char *in, char stop);
char x2c(char *x);
void unescape_url(char *url);
static void salir_bien(PGconn *conn);

/* Almacenamiento temporal de la variable de ambiente */
char *cp;
char *empty = "<vacio>";


	char *qs;	/* qs servira para guardar la cadena de consulta */

	int i,j;
	const char *conninfo;
	PGconn	   *conn;
	PGresult   *res;
	char cadSQL[8000];
	
/* Macro para desplegar las variables de ambiente */
#define safenv(a) ( (cp = getenv(a)) ? cp : empty)

int main(int argc, char **argv)
{
	/* Enviar primero el encabezado MIME */
	printf("Content-type: text/html\n\n");
	
	/* Iniciar una conexion a Postgres con los datos especificados */
	conn = PQsetdbLogin("localhost", NULL, NULL,NULL, "prueba","postgres", "12345");

	/* Comprobar si la conexion fue creada correctamente */
	if (PQstatus(conn) != CONNECTION_OK)
	{
		fprintf(stderr, "La conexion a la BD ha fallado: %s",	PQerrorMessage(conn) );
		salir_bien(conn);
	}

	/* Asignar la cadena de consulta a qs, abortar si esta vacia */
	if((qs = getenv("QUERY_STRING")) == NULL )
	{
		printf("No hay cadena de consulta a decodificar!<br> ");
		exit(1);
	}

	/* Dividir cada uno de los parametros de la cadena de consulta */
	for(i=0; qs[0] != '\0'; i++)
	{
	 /* Primero dividir por '&' cada parametro */
	 splitword(elementos[i].valor,qs,'&');
	 /* Convertir la cadena para caracteres exadecimales y signos mas */
	 unescape_url(elementos[i].valor);
	 /* separar ahora name y value */
	 splitword(elementos[i].nombre,elementos[i].valor,'=');    
	 
	}

	//Titulo de la pagina web
	printf("<HTML><HEAD><TITLE>Alta de un nuevo alumno</TITLE></HEAD>\n");
	//Cuerpo de la pagina web
	printf("<BODY bgcolor='#C9FF5C'>");

	printf("<br>Guardando... ");
  	guardar();		//Realizar el insert

	printf("<font color=\"blue\">Los siguientes datos fueron guardados (excepto el boton):</font><br>");
	for(i=0; elementos[i].nombre[0]; i++)
	 printf("<b>%s</b>=%s<br>",elementos[i].nombre,elementos[i].valor);
  	
	PQclear(res);
	
	//Cerrar la conexion a la BD y limpiar
	PQfinish(conn);
	
	printf("<br><form name=\"volver_indice\" action=\"http://localhost/lpq/index.html\" method=\"POST\">");
	printf("<input type=\"submit\" name=\"volver\" value=\"Volver al menu principal\">");
	printf("</form>");
	printf("</BODY>");

	return 0;
}

/* funcion del Libro */
void splitword(char *out, char *in, char stop)
{
  int i,j;

  for(i=0; in[i] && ( in[i] != stop ); i++)  
    out[i] = in[i];
  
  out[i] = '\0'; 	/* Terminar */
  if( in[i] )
    i++;

  for( j=0; in[j]; )
    in[j++] = in[i++];
}

/* funcion del Libro */
char x2c(char *x)
{
  register char c;
  /* NOTA: (x & oxdf) cambia a mayusculas a x */
  c = ( x[0] >= 'A' ? ( (x[0] & 0xdf) - 'A') +10 : ( x[0] -'0' ));
  c *= 16;
  c += (x[1] >= 'A' ? ( (x[1] & 0xdf) - 'A') +10 : ( x[1] -'0' ));
  return(c);
}

/* funcion del Libro */
void unescape_url(char *url)
{
  register int i,j;

  for(i=0, j=0; url[j]; ++i,++j)
  {
    if( (url[i] = url[j]) =='%' )
    {
      url[i] = x2c(&url[j+1]);
      j += 2;      
    }
    else if(url[i] == '+')
	  url[i] = ' ';
  }
  
  url[i] = '\0';	/* Terminar en la nueva longitud */
}

/*
	Guardar la lista de contactos que esta en la estructura de arrays en un archivo de disco.
*/
void guardar(void)
{
	/* Salvar los datos del StringQuery en la Estructura de datos */
	strcat(lista_alumnos.nc,elementos[0].valor);
	strcat(lista_alumnos.nombre, elementos[1].valor);
  	strcat(lista_alumnos.apellidos, elementos[2].valor);
  	strcat(lista_alumnos.direccion, elementos[3].valor);
  	
	lista_alumnos.estatura = atof(elementos[4].valor); 
	lista_alumnos.peso = atof(elementos[5].valor);
  	
  	strcat(lista_alumnos.fecha_ingreso, elementos[6].valor);
  	strcat(lista_alumnos.fecha_ingreso, "-");  
  	strcat(lista_alumnos.fecha_ingreso, elementos[7].valor); 
  	strcat(lista_alumnos.fecha_ingreso, "-");
  	strcat(lista_alumnos.fecha_ingreso, elementos[8].valor); 
  	
  	strcat(lista_alumnos.carrera, elementos[9].valor);
  	strcat(lista_alumnos.sexo, elementos[10].valor);
	
	/* Unir en una sola cadena los datos a insertar (formar la operacion insert de SQL) */
	strcat(cadSQL, "INSERT INTO alumnos VALUES(");
	strcat(cadSQL, "\'");	strcat(cadSQL, lista_alumnos.nc);					strcat(cadSQL, "\',");
	strcat(cadSQL, "\'");	strcat(cadSQL, lista_alumnos.nombre);				strcat(cadSQL, "\',");
	strcat(cadSQL, "\'");	strcat(cadSQL, lista_alumnos.apellidos);			strcat(cadSQL, "\',");
	strcat(cadSQL, "\'");	strcat(cadSQL, lista_alumnos.direccion);			strcat(cadSQL, "\',");
	strcat(cadSQL, elementos[4].valor);			strcat(cadSQL, ",");
	strcat(cadSQL, elementos[5].valor);			strcat(cadSQL, ",");	
	strcat(cadSQL, "\'");	strcat(cadSQL, lista_alumnos.fecha_ingreso);		strcat(cadSQL, "\',");
	strcat(cadSQL, "\'");	strcat(cadSQL, lista_alumnos.carrera);				strcat(cadSQL, "\',");
	strcat(cadSQL, "\'");	strcat(cadSQL, lista_alumnos.sexo);					strcat(cadSQL, "\'");
	strcat(cadSQL, ")");

	/*Ejecutar la operacion SQL en el servidor */
	res = PQexec(conn, cadSQL);
	
	/* Si la operacion salio bien, mostrar un MSG, sino tbn (jejeje) */
	if ( PQresultStatus(res) == PGRES_COMMAND_OK )
	{
	printf(" ok");
		printf("<br>Estado de comando INSERT: %s<br><br>", PQresStatus(PQresultStatus(res)));
	}
	else
	{
		printf("Estado de la operacion SQL (insert): %s<br>", PQresStatus(PQresultStatus(res)));
	}
}

static void salir_bien(PGconn *conn)
{
	PQfinish(conn);
	exit(1);
}

Y aca se muestra una imagen con la pagina que muestra este programa en el navegador, despues de haber realizado la operacion INSERT en la tabla:


Como es de suponerse el usuario debe dar click en el boton para volver a la pagina principal.

formularioBajas.html
Por otra parte si en el menu de la pagina principal (index.html) el usuario da click en el boton Dar de baja entonces se abrira la pagina web de este achivo. Esta pagina tiene como objetivo capturar el Numero de control (n.c.) de un alumno al cual se desea dar de baja. Al dar click en el boton Dar de baja se enviara este numero de control a un programa CGI llamado bajaAlumnos.cgi que sera el que borrara al alumno con ese n.c. Este archivo esta almacenado en /usr/local/servidor_web/htdocs/lpq. Bueno a continuacion muestro el contenido de este este archivo:

<!--		Instituto Tecnologico de Zacatepec
    Descripcion:
    Formulario de datos que se usara para leer el NC del alumno que se dara de baja	 y enviarlo a un programa CGI
    Author:     Gonzalo Silverio  gonzasilve@gmail.com
    Archivo:    formularioBajas.html
-->
<html>
<head>
<title>Baja de un alumno</title>
</head>
<body bgcolor="#C9FF5C">
    <br>
    <form name="form_bajas" action="http://localhost/cgi-bin/lpq/bajaAlumnos.cgi" method="GET">
        <br>
        <table width="90%" border="1" align="center" bgcolor="#FFFFFF" >
            <tr>
                <td>
                    <table border="0" cellspacing="0" align="center" width="100%">
                        <tr>
                            <td colspan="2" bgcolor="#6D6DFF"><h2 align="center">
                                <font color="white"><br><img src="logo_web.gif" alt="gonzasilve">
                                    Baja de un alumno
                                </font></h2>
                            </td>
                        </tr>
                        <tr>
                            <td align="center"><br><br>
                                <b>Escriba el N.C del alumno<br> que desea dar de baja:</b><br>
                                <input type="text" name="nc" size="30" maxlength="10"><br><br>
                            </td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
      <br><br>
      <table border="0" width="80%" align="center">
            <tr>
                <td colspan="2" align="center">
                    <input type="submit" name="baja" value="Dar de baja">&nbsp;&nbsp;&nbsp;
                </td>
                <td colspan="2" align="center">
                    <input type="reset" name="limpiar" value="Limpiar">&nbsp;&nbsp;&nbsp;
                </td>
                <td colspan="2" align="center">
                    <input type="Button" name="cancelar" value="Cancelar baja" onClick="location='http://localhost/lpq/index.html'">
                </td>
            </tr>
       </table>
    </form>
</body>
</html>

Y ahora la siguiente imagen muestra esta pagina en el navegador:

bajaAlumnos.cgi
Este archivo es un programa CGI y recibe a travez del formulario del archivo formularioBajas.html el n.c. de un alumno que se desea dar de baja. Despues de que recibe el n.c. establece una conexion con la BD y ejecuta una operacion DELETE sobre la tabla alumnos.Este archivo esta almacenado en /usr/local/servidor_web/cgi-bin/lpq. A continuacion A continuacion se muestra el codigo fuente en C de este programa CGI:


/*
	Instituto Tecnologico de Zacatepec
  Descripcion:	Programa que hace un DELETE para dar de baja a un alumno en una tabla de postgres
  Author:	Gonzalo Silverio  gonzasilve@gmail.com
  Archivo:	bajaAlumnos.c
  Compilar con: 
		cc -c -I/usr/local/pgsql/include bajaAlumnos.c
  Enlazar CGI con libreria LPQ con:
  		cc -o bajaAlumnos.cgi bajaAlumnos.o -L/usr/local/pgsql/lib -lpq
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "libpq-fe.h"

// Maximo 100 registros de alumnos
#define MAX 100

// Estrutura de datos que guarda los nombres de las variables CGI y sus valores de los formularios
struct 
{
  char nombre[128];
  char valor[128];
} elementos[MAX];


void  baja(void);

// declaraciones de las funciones que se van a utilizar en el programa
void splitword(char *out, char *in, char stop);
char x2c(char *x);
void unescape_url(char *url);
static void salir_bien(PGconn *conn);

// Almacenamiento temporal de la variable de ambiente
char *cp;
char *empty = "<vacio>";


	char *qs;	/* qs servira para guardar la cadena de consulta */

	int i,j;
	PGconn	   *conn;
	PGresult   *res;
	char cadSQL[8000];

int main(int argc, char **argv)
{
	// Enviar primero el encabezado MIME
	printf("Content-type: text/html\n\n");
	
	// Iniciar una conexion a Postgres con los datos especificados 
	conn = PQsetdbLogin("localhost", NULL, NULL,NULL, "prueba","postgres", "12345");

	// Comprobar si la conexion fue creada correctamente 
	if (PQstatus(conn) != CONNECTION_OK)
	{
		fprintf(stderr, "La conexion a la BD ha fallado: %s",	PQerrorMessage(conn) );
		salir_bien(conn);
	}

	// Asignar la cadena de consulta a qs, abortar si esta vacia
	if((qs = getenv("QUERY_STRING")) == NULL )
	{
		printf("No hay cadena de consulta a decodificar!<br> ");
		exit(1);
	}

	// Dividir cada uno de los parametros de la cadena de consulta
	for(i=0; qs[0] != '\0'; i++)
	{
	 // Primero dividir por '&' cada parametro
	 splitword(elementos[i].valor,qs,'&');
	 // Convertir la cadena para caracteres exadecimales y signos mas
	 unescape_url(elementos[i].valor);
	 // separar ahora name y value 
	 splitword(elementos[i].nombre,elementos[i].valor,'=');    
	 
	}

	//Titulo de la pagina web
	printf("<HTML><HEAD><TITLE>baja de un alumno</TITLE></HEAD>\n");
	//Cuerpo de la pagina web
	printf("<BODY bgcolor='#C9FF5C'><br>");

  	baja();
  	
	PQclear(res);
	
	// cerrar la conexion a la BD y limpiar
	PQfinish(conn);
	
	printf("<br><form name=\"volver_indice\" action=\"http://localhost/lpq/index.html\" method=\"POST\">");
	printf("<input type=\"submit\" name=\"volver\" value=\"Volver al menu principal\">");
	printf("</form>");
	printf("</BODY>");

	return 0;
}

/// funcion del Libro 
void splitword(char *out, char *in, char stop)
{
  int i,j;

  for(i=0; in[i] && ( in[i] != stop ); i++)  
    out[i] = in[i];
  
  out[i] = '\0'; 	// Terminar
  if( in[i] )
    i++;

  for( j=0; in[j]; )
    in[j++] = in[i++];
}

// funcion del Libro 
char x2c(char *x)
{
  register char c;
  // NOTA: (x & oxdf) cambia a mayusculas a x
  c = ( x[0] >= 'A' ? ( (x[0] & 0xdf) - 'A') +10 : ( x[0] -'0' ));
  c *= 16;
  c += (x[1] >= 'A' ? ( (x[1] & 0xdf) - 'A') +10 : ( x[1] -'0' ));
  return(c);
}

// funcion del Libro 
void unescape_url(char *url)
{
  register int i,j;

  for(i=0, j=0; url[j]; ++i,++j)
  {
    if( (url[i] = url[j]) =='%' )
    {
      url[i] = x2c(&url[j+1]);
      j += 2;      
    }
    else if(url[i] == '+')
	  url[i] = ' ';
  }
  
  url[i] = '\0';	// Terminar en la nueva longitud 
}

//	Ejecutar Operacion DELETE en el DBMS Postgres
void baja(void)
{	
	// Formar la cadena de la operacion SQL que se quiere mandar al server
	strcat(cadSQL, "DELETE FROM alumnos WHERE nc=\'");
	strcat(cadSQL, elementos[0].valor);
	strcat(cadSQL, "\'");
	
	// Ejecutar la operacion SQL en el servidor 
	res = PQexec(conn, cadSQL);
	
	// Si la operacion salio bien, mostrar un MSG, sino tbn (jejeje)
	if ( PQresultStatus(res) == PGRES_COMMAND_OK )
	{
		printf("<br>baja realizada con exito: %s<br>", PQresStatus(PQresultStatus(res)));
	}
	else
	{
		printf("Estado de la operacion SQL (delete): %s<br>", PQresStatus(PQresultStatus(res)));
	}	
}

static void salir_bien(PGconn *conn)
{
	PQfinish(conn);
	exit(1);
}

Una vez que se a ejecutado la operacion DELETE exitosamente el programa bajaAlumnos.cgi muestra una pagina web, la cual es la siguiente:


y pues nuevamente, el usuario debe dar click en el boton para volver a la pagina principal.

mostrarAlumnos.cgi
Si en la pagina principal el usuario da click en el boton Ver tabla entonces se ejecuta este programa CGI, el cual tiene la funcion de conectarse a la Base de datos y hacer una operacion SELECT para mostrar una pagina web en una tabla los datos de la tabla alumnos. Este archivo esta almacenado en /usr/local/servidor_web/cgi-bin/lpq. A continuacion el codigo fuente en C del programa CGI:

/*
	Instituto Tecnologico de Zacatepec
  Descripcion:	Programa CGI que hace un SELECT para mostrar el contenido de la tabla alumnos de postgres
  Author:	Gonzalo Silverio  gonzasilve@gmail.com
  Archivo:	mostrarAlumnos.c
  Compilar con: 
		cc -c -I/usr/local/pgsql/include mostrarAlumnos.c
  Enlazar CGI con libreria LPQ con:
  		cc -o mostrarAlumnos.cgi mostrarAlumnos.o -L/usr/local/pgsql/lib -lpq
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "libpq-fe.h"

void  mostrar(void);
static void salir_bien(PGconn *conn);

int i,j;
PGconn	   *conn;
PGresult   *res;
char cadSQL[8000];

int main(int argc, char **argv)
{
	// Enviar primero el encabezado MIME
	printf("Content-type: text/html\n\n");

	//titulo de la pagina web
	printf("<HTML><HEAD><TITLE>Uso de la libreria LPQ de Postgres</TITLE></HEAD><BODY bgcolor=\'#C9FF5C\'>");
		
	// Iniciar una conexion a Postgres con los datos especificados
	conn = PQsetdbLogin("localhost", NULL, NULL,NULL, "prueba","postgres", "12345");

	// Comprobar si la conexion fue creada correctamente
	if (PQstatus(conn) != CONNECTION_OK)
	{
		fprintf(stderr, "La conexion a la BD ha fallado: %s",	PQerrorMessage(conn) );
		salir_bien(conn);
	}

	printf("<br><h1 align='center'>CGI que usa la libreria LPQ de Postgres</h1>");
	printf("Consultando tabla alumnos......<br><br>");
  	mostrar();
  	
	PQclear(res);
	
	///Cerrar la conexion a la BD y limpiar
	PQfinish(conn);
	
	printf("<br><form name=\"volver_indice\" action=\"http://localhost/lpq/index.html\" method=\"POST\">");
	printf("<center><input type=\"submit\" name=\"volver\" value=\"Volver al menu principal\"></center>");
	printf("</form>");
	printf("</BODY></HTML>");

	return 0;
}


//	Muestra el contenido de la tabla Alumnos.
void mostrar(void)
{
	// Ejecutar la operacion Select SQL en el servidor Postgres
	res = PQexec(conn, "SELECT * FROM alumnos");
	
	// Si la operacion salio bien, mostrar la tabla HTML
	if ( PQresultStatus(res) == PGRES_TUPLES_OK )
	{
		int ntup, nf;
		ntup=PQntuples(res);		
		nf=PQnfields(res);	
		printf("<TABLE width=\'90%%\' BORDER=\'1\' align=\'center\' bgcolor=\'#FFFFFF\'> <TR> <TD align=\'center\'>");
		printf("<TABLE width=\'100%%\' BORDER=\'0\'>");
		printf("<TR bgcolor=\'#c9dfef\'>");
		printf("<TD align=\'center\'><b>N.C</b></TD><TD align=\'center\'><b>Nombre</b></TD><TD align=\'center\'><b>Apellidos</b></TD><TD align=\'center\'><b>Direccion</b></TD><TD align=\'center\'><b>Estatura</b></TD><TD align=\'center\'><b>Peso</b></TD><TD align=\'center\'><b>Fecha ingreso</b></TD><TD align=\'center\'><b>Carrera</b></TD><TD align=\'center\'><b>sexo</b></TD>");
		printf("</TR>");

		for (i=0; i<ntup; i++)
		{
			printf("<TR>");
		   for (j=0; j<nf; j++)
		   {
		   	printf("<TD align=\'center\'> %s </TD>", PQgetvalue(res, i, j));
		   }
			printf("</TR>");
		}
		printf("</TABLE>");
		printf("</TD> </TR></TABLE>");
	}
	else
	{
		printf("ERROR!, Estado de la consulta: %s<br>", PQresStatus(PQresultStatus(res)));
	}
	
}

static void salir_bien(PGconn *conn)
{
	PQfinish(conn);
	exit(1);
}

y aka la imagen con la la pagina web que genera el programa anterior, como se observa previamente e insertado 3 registros para que hubiera algo que mostrar.


Ufff, hasta que al fin acabe con este ejemplo (jejejej algo largo). Como se puede apreciar no pongo mucha explicacion sobre el codigo de los programas CGI, por que el objetivo es tener un apunte a la mano por si lo ocupo despues. Ademas no esta muy complicado de entender si sabes algo de lenguaje C .

Bueno, hasta pronto y espero comentarios o dudas acerca de este ejemplo, o si quieres los fuentes…. deja tu e-mail.

Decodificacion de la variable de ambiente Query_String

Bueno continuo sacando algunos programas CGI de mis apuntes, en este Post quiero mostrar como se puede decodificar la variable de ambiente Query_String recordemos que esta variable es la que contiene los nombres y sus valores de las variables que llegan de un formulario a un programa CGI. El fuente HTML del formulario que se va a enviar al programa CGI es el siguiente:

<!--
	Instituto Tecnologico de Zacatepec
    Descripcion:
    Formulario de datos que se usara en conjunto con el programa decodifica_QueryString.cgi para
    leer los valores que son enviados de este formulario.
    Author:     Gonzalo Silverio  gonzasilve@gmail.com
    Archivo:    formulario.html
-->

<html>
<head>
<title>Decodificar Query String</title>
</head>
<body>
    <br><br><br>
    <form name="formulario1" action="http://localhost/cgi-bin/pruebas/decodifica_QueryString.cgi" method="GET">
        <table width="90%" border="0" align="center" cellspacing="0">
        <tr>
            <td colspan="2" bgcolor="#6D6DFF"><h2 align="center">
                    <font color="white"><br>
                        Decodificar la variable Query String
                    </font></h2>
            </td>
        </tr>
        <tr>
            <td bgcolor="#ff9019"><b>N.C:</b> </td><td><input type="text" name="nc" size="30" maxlength="10"> </td>
        </tr>
        <tr>
            <td bgcolor="#ff9019"><b>Nombre:</b> </td><td><input type="text" name="nombre" size="67" maxlength="255"> </td>
        </tr>
        <tr>
            <td bgcolor="#ff9019"><b>Apellidos:</b> </td><td><input type="text" name="apellidos" size="67" maxlength="255"> </td>
        </tr>
        <tr>
            <td bgcolor="#ff9019"><b>Domicilio:</b> </td><td><textarea COLS="60" rows="3"  name="domicilio" ></textarea></td>
        </tr>
        <tr>
            <td bgcolor="#ff9019">
                <b>Edad:</b> </td><td><input type="text" name="edad" size="10" maxlength="10">
                <font color="#a4a2a1">a&ntilde;os</font>
            </td>
        </tr>
        <tr>
            <td bgcolor="#ff9019">
                <b>Estatura:</b> </td><td><input type="text" name="estatura" size="10" maxlength="10">
                <font color="#a4a2a1">mts.</font>
            </td>
        </tr>
        <tr>
            <td bgcolor="#ff9019">
                <b>Peso:</b> </td><td><input type="text" name="peso" size="10" maxlength="10">
                <font color="#a4a2a1">kgs.</font>
            </td>
        </tr>
        <tr>
            <td bgcolor="#ff9019"><b>Fecha de ingreso:</b> </td><td>Dia
                <select name="dia" size="1">
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                    <option value="4">4</option>
                    <option value="5">5</option>
                    <option value="6">6</option>
                    <option value="7">7</option>
                    <option value="8">8</option>
                    <option value="9">9</option>
                    <option value="10">10</option>
                    <option value="11">11</option>
                    <option value="12">12</option>
                    <option value="13">13</option>
                    <option value="14">14</option>
                    <option value="15">15</option>
                    <option value="16">16</option>
                    <option value="17">17</option>
                    <option value="18">18</option>
                    <option value="19">19</option>
                    <option value="20">20</option>
                    <option value="21">21</option>
                    <option value="22">22</option>
                    <option value="23">23</option>
                    <option value="24">24</option>
                    <option value="25">25</option>
                    <option value="26">26</option>
                    <option value="27">27</option>
                    <option value="28">28</option>
                    <option value="29">29</option>
                    <option value="30">30</option>
                    <option value="31">31</option>
                </select>
                <b>Mes</b>
                <select name="mes" size="1">
                    <option value="1">Enero</option>
                    <option value="2">Febrero</option>
                    <option value="3">Marzo</option>
                    <option value="4">Abril</option>
                    <option value="5">Mayo</option>
                    <option value="6">Junio</option>
                    <option value="7">Julio</option>
                    <option value="8">Agosto</option>
                    <option value="9">Septiembre</option>
                    <option value="10">Octubre</option>
                    <option value="11">Noviembre</option>
                    <option value="12">Diciembre</option>
                </select>
                <b>a&ntilde;o</b>
                <input type="text" size="4" maxlength="4" name="anio" value="">
            </td>
        </tr>
        <tr>
            <td bgcolor="#ff9019"><b>Sexo:</b> </td><td>
                <input type="radio" name="sexo" value="hombre">Masculino &nbsp;&nbsp;
                <input type="radio" name="sexo" value="mujer">Femenino
            </td>
        </tr>
        <tr>
            <td colspan="2" align="center"><br><br>
                <input type="submit" name="enviar" value="Enviar datos a CGI">&nbsp;&nbsp;&nbsp;
                <input type="reset" name="limpiar" value="Limpiar">
            </td>
        </tr>
    </table>
    </form>
</body>
</html>

Y su aspecto en el navegador es mas o menos similar a esto:


El usuario una vez que ha llenado los campos da click en el boton Enviar datos a CGI, dicho boton manda a llamar al programa decodifica_QueryString.cgi y este programa es el que recibe los datos del formulario. A continuacion muestro el programa fuente en C del CGI que recibira los datos del formulario anterior y ‘ despedazara’ la variable de ambiente Query_String para obtener los valores de los campos de dicho formulario:

/*
	Instituto Tecnologico de Zacatepec
  Descripcion:	Programa que decodifica la variable de ambiente Query_String obtiendo los
		valores de las variables que se reciben de un formulario.
  Author:	Gonzalo Silverio     gonzasilve@gmail.com
  Archivo: 	decodifica_QueryString.c
*/

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

/* Estrutura de datos que guarda los nombres de las variables CGI y sus valores de los formularios */
struct 
{
  char nombre[128];
  char valor[128];
} elementos[16];

/* declaraciones de las funciones que se van a utilizar en el programa */
void splitword(char *out, char *in, char stop);
char x2c(char *x);
void unescape_url(char *url);

/* Almacenamiento temporal de la variable de ambiente */
char *cp;
char *empty = "<vacio>";

/* Macro para desplegar las variables de ambiente */
#define safenv(a) ( (cp = getenv(a)) ? cp : empty)

main(int argc, char **argv)
{
  char *qs;	/* qs servira para guardar la cadena de consulta */
  int i;

  /* Enviar primero el encabezado MIME */
  printf("Content-type: text/html\n\n");
  
	//Titulo de la pagina web
	printf("<HTML><HEAD><TITLE>Decodificacion de Query_String</TITLE></HEAD>\n");
	//Cuerpo de la pagina web
	printf("<BODY><br>");

  printf("<b>Contenido de la variable sin decodificar: <br>QUERY_STRING =</b> %s <br>",safenv("QUERY_STRING"));
  

  /* Asignar la cadena de consulta a qs, abortar si esta vacia */
  if((qs = getenv("QUERY_STRING")) == NULL )
  {
    printf("No hay cadena de consulta a decodificar!<br> ");
    exit(1);
  }

  /* Dividir cada uno de los parametros de la cadena de consulta */
  for(i=0; qs[0] != '\0'; i++)
  {
    /* Primero dividir por '&' cada parametro */
    splitword(elementos[i].valor,qs,'&');
    /* Convertir la cadena para caracteres exadecimales y signos mas */
    unescape_url(elementos[i].valor);
    /* separar ahora name y value */
    splitword(elementos[i].nombre,elementos[i].valor,'=');    
    
  }

  /* Imprimir todos los valores de formulario */
  printf("<br></b>LAS VARIABLES Y SUS VALORES SON: </b><br><br>");
  for(i=0; elementos[i].nombre[0]; i++)
    printf("%s=%s  <br>",elementos[i].nombre,elementos[i].valor);

	printf("</BODY>");
}

void splitword(char *out, char *in, char stop)
{
  int i,j;

  for(i=0; in[i] && ( in[i] != stop ); i++)  
    out[i] = in[i];
  
  out[i] = '\0'; 	/* Terminar */
  if( in[i] )
    i++;

  for( j=0; in[j]; )
    in[j++] = in[i++];
}

char x2c(char *x)
{
  register char c;
  /* NOTA: (x & oxdf) cambia a mayusculas a x */
  c = ( x[0] >= 'A' ? ( (x[0] & 0xdf) - 'A') +10 : ( x[0] -'0' ));
  c *= 16;
  c += (x[1] >= 'A' ? ( (x[1] & 0xdf) - 'A') +10 : ( x[1] -'0' ));
  return(c);
}

void unescape_url(char *url)
{
  register int i,j;

  for(i=0, j=0; url[j]; ++i,++j)
  {
    if( (url[i] = url[j]) =='%' )
    {
      url[i] = x2c(&url[j+1]);
      j += 2;      
    }
    else if(url[i] == '+')
	  url[i] = ' ';
  }
  
  url[i] = '\0';	/* Terminar en la nueva longitud */
}

…cabe mencionar que parte del codigo que muestro no es de mi propia cosecha pues lo saque de un libro que me pidieron que consultara y cuyo titulo y autor ahora no recuerdo su nombre, pero en cuanto recuerde lo pongo para que lo consulten, esta muy bueno el libro, bueno aca la compilacion del programa anterior:

y por ultimo muestro lo que arroja el programa CGI decodifica_QueryString.cgi una vez que a decodificado la variable de ambiente Query_String:

buen, espero comentarios o dudas o si les interesan los fuentes, adelante basta dejar su correo. Hasta pronto y gracias x pasar por aqui.

Programa CGI: Lectura de variables de ambiente

En esta ocasion muestro como se pueden leer las variables de ambiente. Recordemos que las variables de ambiente son variables que existen dentro de cada cliente y nos permiten recuperar ciertas caracteristicas acerca de dicho cliente y del servidor donde se ejecuta el programa CGI. Bueno aca el programa fuente:

/*
	Instituto Tecnologico de Zacatepec
 Descripcion:		Lectura de las variables de ambiente con C
 Author: 	Gonzalo Silverio	gonzasilve@gmail.com
 Archivo:	leerVariablesCGI.c
*/

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

// almacenamiento temporal de la variable de ambiente
char * cp;
char * empty = "<empty>";

main(int argc, char ** argv)
{
  // enviar el encabezado de tipo mime
  printf("Content-type: text/html\n\n");

  // Macro para desplegar la variables de ambiente
  #define safenv(a) ((cp = getenv(a)) ? cp : empty)

//Titulo de la pagina web
 printf("<HTML><HEAD><TITLE>Leer Variables de ambiente</TITLE></HEAD>\n");
//Cuerpo de la pagina web
 printf("<BODY><br><b>Las Variables de ambiente son:</b><br><br>");

  // A continuacion vamos a desplegar todas las variables estandar de CGI
  printf("GATEWAY_INTERFACE = %s <br>",safenv("GATEWAY_INTERFACE"));
  printf("REQUEST_METHOD = %s <br>",safenv("REQUEST_METHOD"));
  printf("SCRIPT_NAME = %s <br>",safenv("SCRIPT_NAME"));
  printf("QUERY_STRING = %s <br>",safenv("QUERY_STRING"));
  printf("SERVER_SOFTWARE = %s <br>",safenv("SERVER_SOFTWARE"));
  printf("SERVER_NAME = %s <br>",safenv("SERVER_NAME"));
  printf("SERVER_PROTOCOL = %s <br>",safenv("SERVER_PROTOCOL"));
  printf("SERVER_PORT = %s <br>",safenv("SERVER_PORT"));
  printf("HTTP_USER_AGENT = %s <br>",safenv("HTTP_USER_AGENT"));
  printf("HTTP_ACCEPT = %s <br>",safenv("HTTP_ACCEPT"));
  printf("PATH_INFO = %s <br>",safenv("PATH_INFO"));
  printf("PATH_TRANSLATED = %s <br>",safenv("PATH_TRANSLATED"));
  printf("REMOTE_HOST = %s <br>",safenv("REMOTE_HOST"));
  printf("REMOTE_ADDR = %s <br>",safenv("REMOTE_ADDR"));
  printf("REMOTE_USER = %s <br>",safenv("REMOTE_USER"));
  printf("REMOTE_IDENT = %s <br>",safenv("REMOTE_IDENT"));
  printf("AUTH_TYPE = %s <br>",safenv("AUTH_TYPE"));
  printf("CONTENT_TYPE = %s <br>",safenv("CONTENT_TYPE"));
  printf("CONTENT_LENGTH = %s <br>",safenv("CONTENT_LENGTH"));
  printf("</BODY>");
}

aka la compilacion:

Compilacion lectura de variables de ambiente

…y ahora la ejecucion en el navegador, como se ve algunas variables no tienen valor, lo que quiere decir que tienen un valor 0 ho que simplemente no tienen nada.

Ejecucion de prog. CGI que lee variables de ambiente.

bueno eso es todo y espero comentarios o dudas.

CGI del Clasico Hola mundo en C

Ando un poco aburridon y ps para recapitular un poco sobre lo aprendido en mi materia de programacion web, pues en esta ocasion nada mas dejo el CGI del clasico Hola Mundo, escrito en lenguaje C.

/*
		Instituto Tecnologico de Zacatepec
	Descripcion: Version CGI del clasico programa Hola Mundo
	Author: Gonzalo Silverio  gonzasilve@gmail.com
	Archivo: HolaMundo.c
*/

#include<stdio.h>
main( int argc, char **argv)
{
	//Enviar el encabezado de tipo mime
	printf("Content-type: text/html\n\n");

	//Titulo de la pagina web
	printf("<HTML><HEAD><TITLE>Practica con CGI</TITLE></HEAD>\n");
	//Cuerpo de la pagina web
	printf("<BODY><br><H1 align='center'>Hola Mundo de CGI's</H1>");
	printf("<BR><B></BODY></HTML>\n");
}

Aka el pantallazo de la compilacion para que vean que si furula:

Compilacion de clasico CGI Hola Mundo en C

y ahora la ejecucion en el navegador:

Ejecucion de clasico CGI Hola Mundo en C

como se ve es algo muy basico pero me sirve para tener algun apunte y tbn espero dudas y comentarios.

A %d blogueros les gusta esto: