Foros del Web » Programación para mayores de 30 ;) » Programación General »

Alguien Que Me Ayude!!!

Estas en el tema de Alguien Que Me Ayude!!! en el foro de Programación General en Foros del Web. Quisiera saber si alguien me puede ayudar ya que en mi trabajo me pidieron en la pagina que tienen haya un formulario para inscribirse en ...
  #1 (permalink)  
Antiguo 19/08/2003, 18:43
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Alguien Que Me Ayude!!!

Quisiera saber si alguien me puede ayudar ya que en mi trabajo me pidieron en la pagina que tienen haya un formulario para inscribirse en una competencia, y empece a buscar informacion y vi que para poder procesar el formulario, hay que hacer un programa CGI, y de los lenguajes posibles, el mas parecido al que yo se, que es pascal, es el C. Asi que me estuve bajando de internet manuales, tutoriales, etc. y mas o menos lo pude entender. Asi que despues empece a buscar como hacer un cgi y estoy tratando de hacerlo pero me cuesta un poco, ya que todavia hay bastantes cosas de C que no conozco ya que hace menos de una semana que lo vi por primera vez, y este trabajo que me piden es para dentro de no mas de 10 dias. Ellos lo que quieren es que una vez que la persona complete el formulario, aparezca un nro de inscripcion (del 1 al 1000) y que los datos queden guardados en algun lugar para despues revisarlos.
Yo estoy tratando de hacer la parte de cuando el programa recibe todos los datos juntos (metodo post) y hay que separarlos de acuerdo al campo (nombre, email, etc). El problema es que cuando lo compilo me dice que tiene bastantes errores y no se cuales son o si hay cosas que tengo que agregarle.
Yo lo que hice aca es para que nada mas busque los datos ingresados en nombre, lo otro despues se lo agregaria y despues tendria que ver como hago para guardarlos en un archivo.
Bueno, si alguien me ayuda le agradeceria mucho.

Esto es lo que hice hasta ahora:



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

void Recibe_parametros(char **param);
void Identifica_variable(char *vble, char **param, int *p);
void Transforma_ASCCI(char **param, int *n, char *vble, int *i);

int main()
{
char *cadena, nombre[40];
int p=0;

Recibe_parametros(&cadena);
Identifica_variable(nombre, &cadena, p);
system("PAUSE");
return 0;
}



void Recibe_parametros(char **param);
/* Guarda en "cadena" toda la informacion del formulario
(enviado con el metodo POST) */

{
int longitud;

longitud = atoi(getenv("content_length"));
*param = (char*)malloc((longitud+1)*sizeof(char));
gets(*param);
}



void Identifica_variable(char *vble, char **param, int *n);
/* Recibe un puntero a la variable donde se guardarán los datos del campo, la
cadena donde buscará esos datos y la posicion actual del puntero de la cadena */

{
int i=0;

while(*param != '=')&&(*param != '\0');
{
*param++;
n++;
}
if(*param == '='){
*param++;
n++;
while(*param == '+');
{
*param++;
n++;
}
while(*param != '&')&&(*param != '\0');
{
if(*param == '%');
Transforma_ASCCI(&param, n, vble, i);
else
if(*param == '+');
*param=' ';
vble[i]=*param;
i++;
*param++;
n++;
}
}
else
vble[i]=' ';
}



void Transforma_ASCCI(char **param, int *n, char *vble, int *i);
/* Transforma los caracteres especiales a ascci. El caracter transformado es
guardado en vble[i] */

{
if(
((*param[n+1] >= '0' && *param[n+1] <= '9')||
(*param[n+1] >= 'A' && *param[n+1] <= 'F')
)
&&
((*param[n+2] >= '0' && *param[n+2] <= '9')||
(*param[n+2] >= 'A' && *param[n+2] <= 'F'))
)
{
if(*param[n+1] >= 'A')
vble[i]=((*param[n+1]-'A')+10)*16;
else
vble[i]=(*param[n+1]-'0')*16;
if(*param[n+2] >= 'A')
vble[i]+=(*param[n+2]-'A')+10;
else
vble[i]+=(*param[n+2]-'0');
*param=*param+3;
n=n+3;
i++;
}
  #2 (permalink)  
Antiguo 20/08/2003, 03:06
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola mi amigo,

El problema que tienes entre manos es muy interesante, y me parece realmente fascinante que estés usando C como lenguaje de programación, especialmente cuando lo has preferido aun sin tener mucha experiencia con él, como nos cuentas.

Antes de continuar quiero hacer una aclaración. Para procesar información enviada por formularios web no es completamente necesario usar un programa orientado a CGI. Es solo uno de los caminos. Otras alternativas podrían involucrar el uso de tecnologías como PHP, ASP, y demás, que no necesariamente operan sobre la interfaz CGI.

Claro está que CGI es una opción válida, y resulta particularmente interesante cuando se construyen aplicaciones binarias en lenguajes como C.

Bueno, te voy a presentar una modificación del código que has compartido con nosotros --el cual, dicho sea de paso, me sorprende bastante proviniendo de alguien que, como lo has dicho, conoció C hace menos de una semana. ¿Sólo conoces Pascal por ahora? Por curiosidad, y si no es mucha indiscreción, ¿qué clase de profesión tienes? Si no eres programador, al menos debo decirte que tienes una tremenda disposición para este oficio... :)

Adicionalmente, quisiera preguntarte, ¿sobre qué tipo de entorno trabajas (sistema operativo, servidor web, compilador de C) (algo (system("PAUSE")) me dice que podría ser windows)?

En fin, pasemos a la parte divertida... (el código, por supuesto)

Código:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>


void Recibe_parametros(char **param);
int  Identifica_variable(char *vble, char *param, int *n, int limite);
char Transforma_ASCII(char *cadena);


int main()
{
    char *cadena = NULL;
    char nombre[40];
    int p=0;

    Recibe_parametros(&cadena);

    /* Imprimir cabecera HTTP para cumplir con un requisito de la
     * interfaz CGI */
    printf ("Content-Type: text/html\n\n");

    printf ("Los valores recibidos mediante el metodo POST son:\n");

    while (Identifica_variable(nombre, cadena, &p, 40))
        printf ("  %s\n", nombre);

    if (cadena)
        free(cadena);  /* Liberar la memoria de `cadena' */

/*    system("PAUSE");  */

    return 0;
}


/* Guarda en "cadena" toda la informacion del formulario (enviado con
   el metodo POST) */

void Recibe_parametros(char **param)
{
    /* Variables para almacenar apuntadores a valores de variables de
     * entorno */
    char *content_type;
    char *content_length;

    size_t longitud;

    content_type   = getenv ("CONTENT_TYPE");
    content_length = getenv ("CONTENT_LENGTH");

    if (content_length && (!content_type ||
        strcmp (content_type, "application/x-www-form-urlencoded") == 0)) {

        longitud = (size_t)atoi(content_length);
        *param = (char *)malloc((longitud+1)*sizeof(char));
        fread (*param, sizeof(char), longitud, stdin);
    }
}


/* Recibe un puntero a la variable donde se guardaran los datos del
   campo, la cadena donde buscara esos datos, la posicion actual del
   puntero de la cadena, y un limite maximo de caracteres a
   leer. Devuelve cero si no hay mas valores disponibles, o 1 de lo
   contrario. */

int Identifica_variable(char *vble, char *param, int *n, int limite)
{
    int i=0;

    if (!param)
        return 0;

    param += *n;  /* Ir a la posicion n */

    /* Ignorar el nombre de la variable, ir directo al valor */
    while(*param != '=' && *param != '\0')
    {
        param++;
        (*n)++;
    }

    if(*param == '='){
        param++;
        (*n)++;

        while(*param != '&' && *param != '\0' && i < limite - 1)
        {
            switch (*param) {
            case '%':
                vble[i++] = Transforma_ASCII(param);
                param += 2;
                *n += 2;
                break;

            case '+':
                vble[i++] = ' ';
                break;

            default:
                vble[i++] = *param;
            }
            param++;
            (*n)++;
        }

        vble[i] = '\0';

        return 1;
    }
    else
        return 0;
}


/* Transforma una secuencia hexadecimal `%xx' por el caracter
 * correspondiente segun su valor ASCII. */

char Transforma_ASCII(char *cadena)
{
    char secuencia[3];
    unsigned valor;

    if (*cadena != '%')
        return '?';  /* Devolver un signo de interrogacion si no se
                      * recibe una secuencia valida */

    strncpy (secuencia, cadena + 1, 2);

    secuencia[2] = '\0';
    sscanf (secuencia, "%x", &valor);

    return (char)valor;
}
Espero que pueda serte útil por el momento. Eventualmente podemos reconsiderar el problema, cambiar cosas, buscar otros caminos... El problema es bonito y tenemos unos cuantos días de plazo ¿no es así? :)

Un cordial saludo
  #3 (permalink)  
Antiguo 20/08/2003, 12:36
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Bueno, te agradezco infinitamente que hayas respondido y hayas hecho lo que hiciste con el programa, la verdad que nunca me hubiera imaginado que alguien haga lo que hiciste, muchas gracias.
Te cuento que estoy estudiando ingenieria en sistemas (estoy en 2do) y el unico lenguaje que se es pascal. En cuanto a lo otro que me preguntas, tengo windows 98 y el compilador de c que tengo es el unico que pude conseguir en estos dias por internet que se llama Bloodshed Dev-C++. El servidor web que me preguntas, si te referis a donde esta alojada la pagina, es Arnet.
Bueno, ahora te voy a tener que preguntar algunas (varias) cosas del codigo que hiciste que no entiendo:
- Quisiera ver si me podes explicar mas o menos la funcion Recibe_parametros, ya que la que yo tenia la habia conseguido en internet, pero la verdad que mucho no la entendia. Y en esta hay cosas que no se bien que hacen o para que son, por ejemplo size_t longitud, la condicion del if, la asignacion de *param, el fread.
- La funcion Transforma_ASCCI no veo en que momento hace la transformacion, me imagino que debe ser en sscanf, pero no tengo idea que hace eso.
- Que es if (!param)? pregunta si la variable esta vacia?. Lo mismo con if (cadena).
- El system ("Pause") no lo pongo, no?

Bueno, por ahora eso es todo, ojala que puedas seguir ayudandome asi lo puedo terminar. Despues te tendria que preguntar lo del tema que queden los datos guardados en un archivo, pero eso despues te consulto, ok?. Hasta luego!
  #4 (permalink)  
Antiguo 21/08/2003, 06:22
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola germanst,

Bueno, vamos por partes.. :)


Cita:
Quisiera ver si me podes explicar mas o menos la funcion Recibe_parametros (...) en esta hay cosas que no se bien que hacen o para que son, por ejemplo size_t longitud, la condicion del if, la asignacion de *param, el fread
Bien, veamos:
  • El tipo de datos size_t es usado para manipular cantidades numéricas que de alguna forma representan el tamaño o longitud de algo. Muchas veces funciona como alias de un tipo de dato ``unsigned long int''. Por ejemplo, en algún archivo de cabecera (aquellos que terminan en la extensión `.h') podría estar definido de esta forma:

    Código:
    typedef unsigned long int size_t;
    
  • La siguiente condición:

    Código:
    content_length && (!content_type ||
    strcmp (content_type, "application/x-www-form-urlencoded") == 0)
    
    Básicamente revisa que: el valor de `content_length' no sea NULL ('\0') y que al mismo tiempo suceda una de dos cosas: o bien que `content_type' sea NULL, o que el contenido de `content_type' coincida con la cadena "application/x-www-form-urlencoded". Esto debido a que la función strcmp() de la librería string.h recibe apuntadores a dos cadenas y devuelve un cero si ambas cadenas resultan ser equivalentes.
  • La asignación de `*param' tiene que ver con la gestión dinámica de memoria. Te aconsejo que para más detalles consultes libros de C o material de referencia variado, ya que por sí solo este es un tema bastante extenso como para cubrirlo en un mensaje como éste.

    Básicamente la expresión puede ser descrita de la siguiente manera: reserve memoria mediante la función malloc() y almacene el apuntador al segmento de memoria reservado en `*param'.

    El segmento presente antes del llamado a malloc, (char *), es lo que se conoce como casting o moldeado de datos, que obliga a que la referencia devuelta por malloc() sea tratada como un apuntador a `char' (esto del moldeamiento de datos tiene sentido cuando se está familiarizado con la forma en que se hacen las cosas en C. No tienes que preocuparte mucho con este tipo de cosas por ahora... :)

    La expresión que es enviada como argumento a malloc() indica la cantidad de memoria que debe ser reservada: (longitud+1)*sizeof(char). Esto quiere decir: reserve tantos bytes de memoria como el resultado de sumar uno al valor de `longitud' y multiplicarlo por el espacio de memoria que ocupa un valor tipo `char'. La gracia de sumar 1 a `longitud' es que en C las cadenas suelen manipularse como referencias a datos tipo `char' que apuntan a una secuencia de caracteres ubicados en la memoria. Para delimitar el fin de la cadena, se usa un caracter especial, el NULL, '\0', y por esto reservamos memoria contando el espacio adicional para éste caracter.
  • La siguiente sentencia:

    Código:
    fread (*param, sizeof(char), longitud, stdin);
    
    Quiere decir más o menos lo siguiente: leer desde el descriptor de archivo `stdin' tantos datos como indique el valor de `longitud', asumiendo que cada dato es de tamaño `sizeof(char)', y almacenar la información leída en `*param'.

    En C, el descriptor de archivo especial `stdin' es una referencia que apunta a la entrada estándar del sistema, la cual generalmente está asociada con un dispositivo de entrada como el teclado, aunque en nuestro caso en particular usamos `stdin' para leer la entrada que proviene desde la interfaz CGI.

    Para más información, puedes consultar en algún libro o en otras fuentes de información sobre la sintaxis y el propósito de la función fread(), que hace parte de la librería estándar stdio.h.


Cita:
La funcion Transforma_ASCCI no veo en que momento hace la transformacion, me imagino que debe ser en sscanf, pero no tengo idea que hace eso.
Efectivamente, la "tranformación" ocurre al momento de hacer el llamado a sscanf(). La familia de funciones *scanf() y *printf() (como sscanf(), fscanf(), vscanf(), vsscanf(), vfscanf(), etc.) trabajan todas en base a una cadena que puede contener diferentes especificadores de conversión. Es un tema bonito pero me temo que lo suficientemente extenso como para abandonar la idea de tratar de abarcarlo aquí.

Te diré eso sí que la sentencia:

Código:
sscanf (secuencia, "%x", &valor);
Hace más o menos lo siguiente: leer desde la cadena cuya referencia está almacenada en `secuencia' un valor hexadecimal (indicado por el especificador `%x') que será almacenado en la variable `valor'.

El símbolo `&' que precede a `valor' tiene como propósito enviar tal argumento a la función sscanf() por referencia, lo que implica que debe ser pasada una referencia a la variable, y no el valor mismo de la misma. El operador `&' en C devuelve una referencia hacia una variable determinada (la dirección de memoria asociada con la variable). Si aun no estás muy familiarizado con este concepto, no te preocupes. Tan solo ten en mente que cuando envíes variables tipo `char', o `int', por ejemplo, como argumentos a una función como scanf() o sscanf(), por lo general querrás colocar el operador `&' antes del nombre de cada variable.


Cita:
Que es if (!param)? pregunta si la variable esta vacia?. Lo mismo con if (cadena).
En C, estructuras de control como `if' básicamente controlan el flujo de un programa según el valor al que sea evaluada una determinada expresión. Como en C no existe un tipo de datos booleano nativo, esto por lo general quiere decir que la expresión es verificada por dos posibles casos: si la expresión evalúa a cero, o si la expresión evalúa a cualquier cosa distinta a cero.

Así que, por ejemplo, la expresión:

Código:
if (cadena)
Sería equivalente a:

Código:
if (cadena != 0)
Ya que en ambos casos, la idea es que si el valor de `cadena' evalúa a cualquier cosa distinta a cero, el bloque principal del `if' debe ser ejecutado. Incidentalmente, cabe anotar que 0 es entre otras cosas el valor de la macro NULL. Una de las formas en las que comúnmente es definida tal macro es '\0', lo cual quiere decir "un caracter sencillo igual al valor ASCII asociado con el número decimal 0.

De forma similar, la condición if (!param) chequea si param no es un valor que evalúe a algo distinto a cero. Como probablemente sabrás, el signo de admiración (!) actúa como operador lógico NOT en C.


Cita:
El system ("Pause") no lo pongo, no?
Yo lo he comentado ya que en mi sistema el comando `Pause' no tiene ningún sentido, y de otra forma no me permitiría la ejecución normal de la aplicación. Pero si quieres usarlo mientras depuras la aplicación en tu máquina, no hay problema, úsalo libremente si deseas... :)


Cita:
Bueno, por ahora eso es todo, ojala que puedas seguir ayudandome asi lo puedo terminar.
Me parece muy bien. Estás en todo tu derecho de preguntar si no has entendido algo, y aquí algo que creo que es común a todos los que visitamos estos foros es nuestro deseo de aprender y de colaborar con quienes desean hacerlo también.

Te deseo la mejor de las suertes.

Un cordial saludo
  #5 (permalink)  
Antiguo 21/08/2003, 21:32
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Hola, bueno, antes que nada te agradezco las explicaciones. Bueno, te cuento que empecé a ver como puedo hacer para guardar los formularios que sean enviados en un archivo, para despues poder acceder a esos datos. Yo creo que si los datos quedaran guardados en un archivo de excel, estaria bueno porque despues con solo bajar el archivo se podria ver todo claramente, pero la verdad que no se si esto es posible o capaz que no se puede o es muy dificil. Yo estuve probando un poco y no me salio.

Lo que hice fue declarar una variable:
FILE *archivo;

despues hice:
archivo = fopen("inscriptos.xls", "a");
(despues de Recibir_parametros)

Y la idea es que dentro del
while (Identifica_variable(nombre, cadena, &p, 40))
vaya guardando los datos ingresados en cada columna (nombre, apellido, etc), todo lo de esa persona en una misma fila.

yo hice:
fputs(nombre,archivo);

pero el problema basicamente esta en que no se si se puede guardar en un xls, y si se podria, antes del while tendria que bajar una fila y despues sí escribir el dato, y despues de escribirlo, que se haga una tabulacion para pasar a la siguiente columna. Pero como ya te dije no se si se puede ni como se haria esto.
Si no se puede esto del excel, en que se podria guardar de forma de que despues ellos puedan agarrar el archivo y leerlo facilmente?
Bueno, espero que me puedas seguir ayudando y que no te canses y me mandes a la m..., porque te debo estar quitando bastante tiempo :) .
  #6 (permalink)  
Antiguo 22/08/2003, 04:02
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Me alegra que vayas progresando. Cuando hablas de FILE *, fopen(), fputs() y demás me parece que vas por buen camino.

Respecto al formato de excel, la verdad es que no lo conozco, y no sé si sea posible almacenar datos en tal formato de una forma relativamente directa. Tendrías que consultar con alguien que conociera más de ese tipo de formatos... :)

Ahora bien, me parece que almacenar los datos en un archivo de texto plano es, al menos en principio, una buena idea. Un estilo usado con frecuencia para almacenar información en archivos planos es por líneas, en donde cada campo es separado por algún caracter delimitador, por ejemplo las tabulaciones (\t).

Considera por ejemplo la siguiente variación de la función main():


Código:
int main()
{
    FILE *da;  /* Descriptor de archivo */

    char *cadena = NULL;
    char nombre[40];
    int p=0;

    Recibe_parametros(&cadena);

    /* Imprimir cabecera HTTP para cumplir con un requisito de la
     * interfaz CGI */
    printf ("Content-Type: text/html\n\n");


#define ARCHIVO_SALIDA  "inscriptos.txt"   /* Archivo en donde se
                                            * almacenan los datos */

    da = fopen (ARCHIVO_SALIDA, "a");

    if (! da) {
        printf ("No pudo abrirse el archivo de salida.\n");
        exit (1);
    }

    printf (
"Guardando los valores recibidos mediante POST en el archivo `%s'.\n",
ARCHIVO_SALIDA);

    while (Identifica_variable(nombre, cadena, &p, 40))
        fprintf (da, "%s\t", nombre);  /* Separar con tabulaciones los
                                        * datos */

    fprintf (da, "\n");  /* Anyadir un salto de linea al final del archivo */
    fclose (da);

    if (cadena)
        free(cadena);  /* Liberar la memoria de `cadena' */

/*    system("PAUSE");  */

    return 0;
}

En esta variación usamos el apuntador `da' (descriptor de archivo) para almacenar datos en un archivo dado (inscriptos.txt) mediante llamados a la función fprintf(). Los datos luego pueden leerse desde el archivo fácilmente, ya que están almacenados en un formato muy simple: cada línea contiene los datos de una petición CGI, y cada campo está separado por tabulaciones. Quizás te sea útil mientras construyes tu propia solución. :)

Un cordial saludo
  #7 (permalink)  
Antiguo 22/08/2003, 18:48
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Hola como andas? Bueno, mira, por suerte con toda la ayuda que me has dado ya casi lo tengo listo, me quedarian un par de cositas, pero ya la parte grande esta.
Te cuento que estuve probando de que se guarde en un excel y se puede, queda bien, haciendo las tabulaciones y nuevas lineas correspondientes como vos me dijiste, asi que buenisimo.
Te digo lo que me falta a ver si me podes dar una mano. La idea es que cada vez que alguien se anote, reciba un nro. de inscripcion. O sea que habria que hacer un archivo que contenga el nro de anotados hasta el momento y una vez que la persona ingrese los datos darle el nro e incrementarlo. Creo que es muy simple, pero no se bien como hacer ese archivo contador.
Yo ahora te voy a pasar el codigo de main como lo tengo ahora y quisiera ver si sabes como se pondria ese numero de inscripcion en la parte donde imprime la cabecera http para que la persona obviamente lo pueda ver.



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


void Recibe_parametros(char **param);
int Identifica_variable(char *vble, char *param, int *n, int limite);
char Transforma_ASCII(char *cadena);


int main()
{
FILE *da, *da2, *cant;
char *cadena = NULL;
char nombre[40];
int p=0;

#define ARCHIVO_SALIDA "inscriptos.xls"
#define ARCHIVO_SALIDA2 "inscrip_copia.xls"
#define ARCHIVO_CANT "contador.txt" /* no se que extencion conviene */

Recibe_parametros(&cadena);

da = fopen(ARCHIVO_SALIDA, "a");
da2 = fopen(ARCHIVO_SALIDA2, "a");
cant = fopen(ARCHIVO_CANT, "a");
if (! da)
exit (1);
if (! cant)
exit (1);

fprintf (da, "\n");
fprintf (da2, "\n");
while (Identifica_variable(nombre, cadena, &p, 40))
{
fprintf (da, "%s\t", nombre);
fprintf (da2, "%s\t", nombre);
}

/* aca tendria que obtener el nro de anotados, guardarlo en una variable, y despues incrementar el nro y guardarlo*/

fclose(da);
fclose(da2);
fclose(cant);


/* Imprime cabecera HTTP para cumplir con un requisito de la
* interfaz CGI */
printf ("Content-Type: text/html\n\n");
printf ("<html>\n");
printf ("<head><title>GRACIAS POR ANOTARSE EN BARADERO 2003</title></head>\n");
printf ("<body bgcolor=#000000 text=#FFFFFF><div align=center>\n");
printf ("<p>&nbsp;</p>\n");
printf ("<p><b><font face=Arial, Helvetica, sans-serif size=4>\n");
printf ("<u>SU NUMERO DE INSCRIPCION ES:</u></font></b></p>\n");
printf ("</div></body>\n");
printf ("</html>\n");


if (cadena)
free(cadena); /* Libera la memoria de `cadena' */

return 0;
}



Por ultimo, tengo alguna forma de ver si todo esto funciona?, porque para subir el cgi me dijeron que se los tengo que mandar a los del servidor, ellos lo controlan y despues lo suben, o sea que se lo mandaria cuando este hecho.
Bueno, espero que puedas ayudarme ya que por suerte (gracias a vos) ya lo estoy terminando. Chau!
  #8 (permalink)  
Antiguo 23/08/2003, 11:13
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola,

Definitivamente percibo progresos considerables en tu código, te felicito. Se nota que tienes espíritu autodidacta y un entusiasmo notable para este oficio. Para mí es un placer y un honor ayudarte en lo que sea posible mientras aprendes este tipo de cosas básicas.

Bien, aquí te presento una modificación más del código de main(). En esta versión, se abre el archivo "contador.txt" en modo de lectura/escritura (r+), con el propósito de leer desde el archivo un valor entero, incrementarlo y finalmente volver a almacenarlo de vuelta. También hay algunos cambios de estilo mínimos, aunque eso ya es una nimiedad que puedes modificar a tu gusto... :)


Código:
int
main()
{
    FILE *da, *da2, *cant;

    char *cadena = NULL;
    char nombre[40];

    int contador = 0;
    int p = 0;


#define ARCHIVO_SALIDA   "inscriptos.xls"
#define ARCHIVO_SALIDA2  "inscrip_copia.xls"
#define ARCHIVO_CANT     "contador.txt"


    Recibe_parametros (&cadena);

    da   = fopen (ARCHIVO_SALIDA,  "a");
    da2  = fopen (ARCHIVO_SALIDA2, "a");


    if (! da || ! da2)
        exit (1);

    fprintf (da,  "\n");
    fprintf (da2, "\n");

    while (Identifica_variable (nombre, cadena, &p, 40)) {
        fprintf (da,  "%s\t", nombre);
        fprintf (da2, "%s\t", nombre);
    }

    fclose (da);
    fclose (da2);


    /* El archivo con el valor del contador se abre en modo de lectura
     * inicialmente */

    cant = fopen (ARCHIVO_CANT, "r+");

    if (! cant)
        exit (1);

    /* Vamos a asumir que el archivo solo contiene un numero entero,
     * el cual podemos leer de forma directa */

    fscanf (cant, "%d", &contador);

    contador++;

    fseek (cant, (long)0, SEEK_SET);  /* Ir al comienzo del archivo */

    fprintf (cant, "%d", contador);

    fclose(cant);


    /* Imprimir una cabecera HTTP requerida por la interfaz CGI y el
     * contenido de un documento HTML */

    printf (
"Content-Type: text/html\n\n"
"<html>\n"
"<head><title>GRACIAS POR ANOTARSE EN BARADERO 2003</title></head>\n"
"<body bgcolor=#000000 text=#FFFFFF><div align=center>\n"
"<p> </p>\n"
"<p><b><font face=Arial, Helvetica, sans-serif size=4>\n"
"<u>SU NUMERO DE INSCRIPCION ES:</u></font></b></p>\n"
"</div></body>\n"
"</html>\n");


    if (cadena)
        free(cadena); /* Libera la memoria de `cadena' */

    return 0;
}

Algunas anotaciones sobre esta versión:
  • Se requiere que el archivo "contador.txt" exista previamente a la ejecución del programa, de otro modo, lo más seguro es que la función fopen() sobre este archivo devuelva NULL.
  • En realidad, me hubiera gustado hacer uso de otras funciones que hubieran facilitado algunos detalles de implementación. Funciones como flock() para implementar un bloqueo de accesos a los archivos, o ftruncate() en medio de las manipulaciones sobre el archivo contador, o fstat() para efectos de mayor legibilidad del algoritmo, pero me he contenido por razones de compatibilidad y simplicidad. Básicamente, no conozco mucho del sistema operativo ni del compilador de C que has contado que usas.

    Eso sí, te animo a que consultes sobre la disponibilidad de funciones como las que he mencionado en tu compilador, de modo que puedas hacer más robusta y escalable tu aplicación.


Finalmente, sobre cómo probar que la aplicación funcione, lo ideal sería que contaras con un servidor web en tu máquina local con soporte para la interfaz CGI, y pudieras allí hacer tus pruebas. Aunque como verás, lo único que requiere esta aplicación para realizar su labor básica es que esté definida la variable de entorno CONTENT_LENGTH con algún valor numérico que indica cuántos bytes serán leídos desde `stdin'. No sé cómo se manejará el tema de variables de entorno en tu sistema, aunque por ejemplo en el mío ejecuto la aplicación de esta forma para realizar pruebas:


$ CONTENT_LENGTH=7 ./ejemplo.cgi
a=b&c=d


La primera línea corresponde a lo que escribo en la línea de comandos (ejemplo.cgi es el nombre del binario de la aplicación), y la segunda línea es el contenido de prueba que escribo por teclado para que esté disponible a la aplicación por medio de `stdin'.

La aplicación en este ejemplo responde con:


Content-Type: text/html

<html>
<head><title>GRACIAS POR ANOTARSE EN BARADERO 2003</title></head>
<body bgcolor=#000000 text=#FFFFFF><div align=center>
<p> </p>
<p><b><font face=Arial, Helvetica, sans-serif size=4>
<u>SU NUMERO DE INSCRIPCION ES:</u></font></b></p>
</div></body>
</html>


De modo que puedo ver que la aplicación parece ejecutarse correctamente. Por supuesto, lo mejor sería probarlo en el entorno real, una vez esté montado en el servidor final.

Por supuesto, creo que está de más decirte que te asegures de que el código fuente sea compilado sin mensajes de error ni advertencias, para restringir nuestro escenario de posibles errores a detalles en tiempo de ejecución. :)

Saludos
  #9 (permalink)  
Antiguo 23/08/2003, 14:55
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Hola, te preguno dos cositas que no me quedaron bien claras.

Yo para que funcione el archivo contador que es lo que tengo que hacer? Tengo que crear un txt en mi maquina y escribir por ejemplo 0 y que el programa utilize ese archivo?

Lo otro es como tengo que hacer para que en la pagina que va a aparecerle a la persona cuando se anota aparezca el numero de inscripcion.
Asi apareceria?:

printf (
"Content-Type: text/html\n\n"
"<html>\n"
"<head><title>GRACIAS POR ANOTARSE EN BARADERO 2003</title></head>\n"
"<body bgcolor=#000000 text=#FFFFFF><div align=center>\n"
"<p> </p>\n"
"<p><b><font face=Arial, Helvetica, sans-serif size=4>\n"
"<u>SU NUMERO DE INSCRIPCION ES: %d</u></font></b></p>\n"
"</div></body>\n"
"</html>\n", contador);

O sea ponerle %d despues del mensaje y al final el nombre de la variable.

Bueno, gracias por todo y espero que me puedas aclarar estas dos cositas y con eso creo que ya estaria terminado. Chau!
  #10 (permalink)  
Antiguo 23/08/2003, 15:33
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Ahh! me olvidaba, cuando lo vaya a subir, como hago para que sea un cgi, ¿al exe que me hace cuando compilo el programa le cambio la extension y le pongo .cgi?
  #11 (permalink)  
Antiguo 23/08/2003, 16:41
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Cita:
Yo para que funcione el archivo contador que es lo que tengo que hacer? Tengo que crear un txt en mi maquina y escribir por ejemplo 0 y que el programa utilize ese archivo?
Sí, con crear un archivo llamado "contador.txt", que puede estar vacío o tener un valor inicial, y colocarlo bajo el mismo directorio en donde esté ubicada la aplicación CGI, debe bastar.


Cita:
Lo otro es como tengo que hacer para que en la pagina que va a aparecerle a la persona cuando se anota aparezca el numero de inscripcion.
Asi apareceria?
El ejemplo que propones está muy bien. Se ve que ya estás adquiriendo la idea del asunto. :)


Cita:
Ahh! me olvidaba, cuando lo vaya a subir, como hago para que sea un cgi, ¿al exe que me hace cuando compilo el programa le cambio la extension y le pongo .cgi?
Eso depende del entorno particular en donde va a correr la aplicación, en especial del servidor web. Usualmente los administradores configuran sus servidores web para que reconozcan a aquellos archivos con la extensión `.cgi' como aplicaciones a ejecutarse a través de CGI. Creo que lo más recomendable es que hables del asunto con las personas encargadas de la máquina servidor en donde vas a montar el programa.


Saludos.
  #12 (permalink)  
Antiguo 25/08/2003, 17:48
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Hola Leonardo, te escribo para agradecerte la ayuda que me diste estos dias con el programa, la verdad que sin tu ayuda nunca lo podria haber hecho. Ahora solo falta que lo suba y probarlo, pero supongo que no va a haber problemas. Cualquier cosa desues te cuento, chau!

Germán.
  #13 (permalink)  
Antiguo 26/08/2003, 13:23
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Como andas? vos sabes que tengo tanta mala suerte que los de arnet (que es donde esta alojada la pagina) dicen que no puedo subir el cgi que hice porque dicen que tiene que ser Pearl/cgi . Sabes de que manera puedo solucionarlo, por ejemplo si existe un web host gratis qu me deje subirlo, o si es mucho quilombo pasarlo a pearl. Bueno, disculpa que te siga jodiendo, lo que pasa que me salieron con esto y me quiro matar, no se que hacer. Saludos!


Germán.
  #14 (permalink)  
Antiguo 27/08/2003, 00:05
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola,

Bueno, sobre sitios de hospedaje no sé mucho, la verdad. Por ese lado no puedo ayudarte mucho.

Sin embargo, sobre la adaptación del código a Perl, ese sí podría ser un ejercicio interesante, y que además considero relativamente trivial.

Si quieres, creo que podemos ayudarte a adaptar el código original de C a Perl. Tan sólo déjanos saber el código fuente del programa original tal como lo tienes en este momento, para poder realizar la "traducción".

Saludos.
  #15 (permalink)  
Antiguo 27/08/2003, 10:16
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
En serio podrias llegar a pasarlo a Pearl?, bueno, la verdad que para mi eso seria buenisimo, de verdad.
Te digo por las dudas lo que me dijeron ellos: "el fuente tiene que estar hecho en CGI/Perl...".
Bueno, yo te mando el codigo tal cual esta ahora, lo unico que tal vez yo antes de subirlo vaya a cambiarle sea el codigo html, pero lo demas quedaria tal cual, salvo una cosa: los tres archivos a los que se hace referencia deben estar en otro directorio, y no se como se hace.
Te cuento, el cgi va a estar en una carpeta llamada cgi-bin, pero los archivos en una carpeta llamada httpdocs, que no esta dentro de cgi-bin, sino que esta al mismo nivel, se entiende?

seria asi:
[principal]
| |
[cgi-bin] [httpdocs]
| |
archivo.cgi {los tres archivos
a los q' se hace referencia}


Bueno, aca va el codigo:



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


void Recibe_parametros(char **param);
int Identifica_variable(char *vble, char *param, int *n, int limite);
char Transforma_ASCII(char *cadena);


int main()
{
FILE *da, *da2, *cant;
char *cadena = NULL;
char nombre[40];
int p=0;
int contador=0;

#define ARCHIVO_SALIDA "inscriptos.xls"
#define ARCHIVO_SALIDA2 "inscrip_copia.xls"
#define ARCHIVO_CANT "contador.txt"

Recibe_parametros(&cadena);

da = fopen(ARCHIVO_SALIDA, "a");
da2 = fopen(ARCHIVO_SALIDA2, "a");
if (! da || ! da2)
exit (1);

fprintf (da, "\n");
fprintf (da2, "\n");
while (Identifica_variable(nombre, cadena, &p, 40))
{
fprintf (da, "%s\t", nombre);
fprintf (da2, "%s\t", nombre);
}

fclose(da);
fclose(da2);

cant = fopen(ARCHIVO_CANT, "r+");
if (! cant)
exit(1);

fscanf (cant, "%d", &contador);
contador++;
fseek (cant, (long)0, SEEK_SET); /* va al comienzo del archivo */
fprintf (cant, "%d", contador);
fclose (cant);


/* Imprime cabecera HTTP para cumplir con un requisito de la
* interfaz CGI */
printf ("Content-Type: text/html\n\n"
"<html>\n"
"<head><title>Gracias por anotarse en Baradero 2003</title></head>\n"
"<body bgcolor=#000000 text=#FFFFFF><div align=center>\n"
"<p>&nbsp;</p>\n"
"<p><b><font face=Arial, Helvetica, sans-serif size=4>\n"
"<u>SU NUMERO DE INSCRIPCION ES: %d</u></font></b></p>\n"
"</div></body>\n"
"</html>\n", contador);


if (cadena)
free(cadena); /* Libera la memoria de `cadena' */

return 0;
}



/* Guarda en "cadena" toda la informacion del formulario (enviado con
* el metodo POST) */

void Recibe_parametros(char **param)
{
/* Variables para almacenar apuntadores a valores de variables de
* entorno */
char *content_type;
char *content_length;

size_t longitud;

content_type = getenv ("CONTENT_TYPE");
content_length = getenv ("CONTENT_LENGTH");

if (content_length && (!content_type ||
strcmp (content_type, "application/x-www-form-urlencoded") == 0)) {

longitud = (size_t)atoi(content_length);
*param = (char *)malloc((longitud+1)*sizeof(char));
fread (*param, sizeof(char), longitud, stdin);
}
}



/* Recibe un puntero a la variable donde se guardaran los datos del
* campo, la cadena donde buscara esos datos, la posicion actual del
* puntero de la cadena, y un limite maximo de caracteres a
* leer. Devuelve cero si no hay mas valores disponibles, o 1 de lo
* contrario. */

int Identifica_variable(char *vble, char *param, int *n, int limite)
{
int i=0, cont=0;

if (!param)
return 0;

param += *n; /* Ir a la posicion n */

/* Ignorar el nombre de la variable, ir directo al valor */
while(*param != '=' && *param != '\0')
{
param++;
(*n)++;
}

if(*param == '='){
param++;
(*n)++;

while(*param != '&' && *param != '\0' && i < limite - 1)
{
cont = 1;
switch (*param) {
case '%':
vble[i++] = Transforma_ASCII(param);
param += 2;
*n += 2;
break;

case '+':
vble[i++] = ' ';
break;

default:
vble[i++] = *param;
}
param++;
(*n)++;
}

if (*param == '&' && cont == 0)
vble[i++] = ' '; /* Si no hay datos en la variable
* (ej: ape=&nom=pepe) */

vble[i] = '\0';

return 1;
}
else
return 0;
}



/* Transforma una secuencia hexadecimal `%xx' por el caracter
* correspondiente segun su valor ASCII. */

char Transforma_ASCII(char *cadena)
{
char secuencia[3];
unsigned valor;

if (*cadena != '%')
return '?'; /* Devolver un signo de interrogacion si no se
* recibe una secuencia valida */

strncpy (secuencia, cadena + 1, 2);

secuencia[2] = '\0';
sscanf (secuencia, "%x", &valor);

return (char)valor;
}



Bueno, te agradezco de antemano la buena voluntad, y seguimos en contacto. Chau!

Germán.
  #16 (permalink)  
Antiguo 27/08/2003, 10:20
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
bueno, ahora veo que el arbol que intente dibujarte quedo diferente a lo que lo hice.
a ver si se entiende asi:

cuando entro al sitio con el ftp, se ven las siguientes carpetas: cgi-bin y httpdocs, en la primera va el cgi y en la otra los tres archivos.
Creo que ahi esta mas claro, capaz que ya lo habias entendido y yo te la estoy complicando al pepe.
  #17 (permalink)  
Antiguo 27/08/2003, 12:23
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Bueno, ha sido un ejercicio divertido adaptar el código a Perl. Aquí está mi primera aproximación:


Código:
#! /usr/bin/perl -w
use strict;

use vars qw($cadena $contador $nombre $p);



### Prototipos de funciones ###

sub Identifica_variable ($$);
sub Recibe_parametros   ();
sub Transforma_ASCII    ($);



### Definicion de valores constantes ###

sub ARCHIVO_SALIDA  () { '../httpdocs/inscriptos.xls' }
sub ARCHIVO_SALIDA2 () { '../httpdocs/inscrip_copia.xls' }
sub ARCHIVO_CANT    () { '../httpdocs/contador.txt' }



### Codigo principal ###

$cadena = Recibe_parametros ();

open (DA,  '>>' . ARCHIVO_SALIDA)  or die $!;
open (DA2, '>>' . ARCHIVO_SALIDA2) or die $!;

print DA "\n";
print DA2 "\n";

$p = 0;
while ($nombre = Identifica_variable ($cadena, \$p)) {
    print DA  "$nombre\t";
    print DA2 "$nombre\t";
}

close (DA2) or die $!;
close (DA)  or die $!;


$contador = 0;

if (! -f ARCHIVO_CANT)
{ open (CANT, '>' . ARCHIVO_CANT) or die $! }
else
{ open (CANT, '+<' . ARCHIVO_CANT) or die $! }

read (CANT, $contador, -s ARCHIVO_CANT);
$contador++;

seek (CANT, 0, 0);  # va al comienzo del archivo
print CANT $contador;

close (CANT) or die $!;


# Imprime cabecera HTTP para cumplir con un requisito de la interfaz
# CGI

print <<FIN_SALIDA;
Content-Type: text/html

<html>
 <head>
  <title>Gracias por anotarse en Baradero 2003</title>
 </head>

 <body bgcolor="#000000" text="#FFFFFF">
  <div align=center>
   <p> </p>
    <p>
     <b><font face=Arial, Helvetica, sans-serif size=4>
     <u>SU NUMERO DE INSCRIPCION ES: ${contador}</u></font></b>
    </p>
  </div>
 </body>
</html>
FIN_SALIDA

exit (0);



### Declaracion de funciones ###

# Recibe la cadena donde buscara los datos pasados desde el formulario
# y una referencia a la posicion actual de procesamiento en la
# cadena. Devuelve el siguiente valor disponible, o 0 si no hay mas.

sub Identifica_variable ($$)
{
    my $cadena  = shift;
    my $ref_pos = shift;

    my $param = substr ($cadena, $$ref_pos);

    return 0 if (! $param or $param eq '');

    
    # Ignorar el nombre de la variable, ir directo al valor

    while ($param !~ /^=/ and $param ne '') {
        $param =~ s/^.//s;
        $$ref_pos++;
    }

    if ($param =~ /^=/) {
        $param =~ s/^.//s;
        $$ref_pos++;

        my $vble = '';
        my $cont = 0;

        while ($param !~ /^&/ and $param ne '')
        {
            $cont = 1 if ! $cont;

            for ($param) {
                /^%/ && do {
                    $vble .= Transforma_ASCII ($param);
                    $param = substr ($param, 2);
                    $$ref_pos += 2;
                    last;
                };

                /^\+/ && do { $vble .= ' '; last; };

                $vble .= substr ($param, 0, 1);
                last;
            }

            $param =~ s/^.//s;
            $$ref_pos++;
        }

        # Si no hay datos en la variable (ej: ape=&nom=pepe)
        $vble .= ' ' if ($param =~ /^&/ and ! $cont);

        return $vble;
    } else
    { return 0 }
}


# Devuelve toda la informacion del formulario (enviado con el metodo
# POST)

sub Recibe_parametros ()
{
    if ($ENV{'CONTENT_LENGTH'} and
        (! $ENV{'CONTENT_TYPE'} or
         $ENV{'CONTENT_TYPE'} eq 'application/x-www-form-urlencoded')) {

        read (STDIN, my $bufer, $ENV{'CONTENT_LENGTH'});

        return $bufer;
    }

    return '';
}


# Transforma una secuencia hexadecimal `%xx' por el caracter
# correspondiente segun su valor ASCII.

sub Transforma_ASCII ($)
{
    my $cadena = shift;

    # Devolver un signo de interrogacion si no se recibe una secuencia
    # valida
    return ($cadena =~ /^%/) ? pack ('c', hex (substr ($cadena, 1, 2))) : '?';
}

Hay algunas cosas que han resultado más bien curiosas debido a que traté en lo posible traducir fielmente la misma lógica del código original. Algunas otras cosas si resultan evidentemente distintas, ya que han tenido que escribirse en "estilo Perl", lo cual no es decir mucho, ya que como bien es sabido, el estilo Perl consiste precisamente en que "hay más de una forma de hacerlo".

Espero que no tengas problema montando la aplicación final en tu servidor. En caso de dudas, discute con la gente encargada del servidor sobre los permisos apropiados que deben otorgarse al archivo del script y al directorio en donde deben ir los archivos de datos.

Saludos.
  #18 (permalink)  
Antiguo 27/08/2003, 20:25
 
Fecha de Ingreso: agosto-2003
Mensajes: 57
Antigüedad: 20 años, 8 meses
Puntos: 0
Buenisimo, te agradezco muchisimo que lo hayas podido pasar, ademas tan rapido. Vos crees que funcionara bien?. Una cosa, con que programa puedo compilarlo? Bajé de perl.com un .zip llamado stable, lo descomprimi, pero no veo como instalarlo. O puedo utilizar eso que baje desde el compilador de C que tengo?. Bueno, gracias de nuevo por la ayuda.
Saludos!
  #19 (permalink)  
Antiguo 27/08/2003, 20:56
 
Fecha de Ingreso: julio-2003
Mensajes: 165
Antigüedad: 20 años, 9 meses
Puntos: 1
Hola de nuevo,

Cita:
Vos crees que funcionara bien?
Sí, eso creo. Lo he probado en mi servidor web local y ha funcionado muy bien. Creo que hace exactamente lo que necesitas.


Cita:
Una cosa, con que programa puedo compilarlo?
Bueno, al menos en distribuciones recientes del intérprete oficial de Perl para sistemas de la familia Unix, sé que viene un compilador real de Perl: `perlcc'.

Pero no creo que necesites de un compilador de Perl realmente. Perl es un lenguaje principalmente conocido por su intérprete. El hecho de que los programas escritos en Perl puedan ser scripts interpretados quiere decir que no necesitas compilarlos. De hecho, la primera línea del código de los programas Perl (como el anterior) suele apuntar a la ruta del intérprete Perl en el sistema, y usa la notación `#!' para que el sistema reconozca el contenido del archivo actual como la entrada que debe ser pasada al intérprete.

En resumen: no es necesario compilar este programa en Perl. Eso sí, debes asegurarte de que la primera línea tenga una referencia correcta a la ruta del intérprete de Perl en el sistema en que vas a montar la aplicación CGI. Esta ruta en mi sistema es `/usr/bin/perl', por ejemplo, pero también podría ser `/usr/local/bin/perl' o algo similar. Nuevamente, te recomiendo que le plantees este tipo de dudas a los encargados del servidor en donde vas a cargar la aplicación. :)

Saludos.
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 06:47.