Backups automáticos de nuestro código fuente (1)

Lo peor que te podría ocurrir en tu vida de programador es que sucediera un desastre y perdieras todo el código fuente de tus aplicaciones. Años de trabajo perdidos, sería algo terrible, muy doloroso, y hasta podría arruinar tu vida profesional.

Para evitar eso, es que debes realizar constantemente backups de tu código fuente y guardarlos en lugares seguros.

Gracias a Internet, uno de esos lugares seguros es «la nube».

Pero claro, estar subiendo manualmente el backup de tu código fuente a «la nube» puede ser bastante aburrido así que lo más probable es que lo hagas a veces, no todos los días. Si es que lo haces.

Una buena alternativa es que esa tarea se realice de forma automática, así siempre estarás protegido te acuerdes o no te acuerdes de realizar el backup. Para ello, existen programas como Google Drive, MegaSync, OfiCloudSync, OneDrive, etc.

En síntesis lo que hacen es sincronizar una carpeta de tu disco duro local con una carpeta en el disco duro remoto. Si les pides que al iniciar sesión en Windows también se ejecuten esos programas entonces estarás siempre protegido. Cada vez que agregues o modifiques algo en una carpeta sincronizada ese cambio se reflejará en la carpeta que se encuentra «en la nube». Muy útil.

Cada uno de esos sitios te provee de una cierta cantidad de gigabytes gratis. Si necesitas más entonces…tendrás que pagar. Pero para realizar backups de nuestro código fuente lo que ofrecen gratis es más que suficiente. Al momento de escribir este artículo:

  • Google Drive te da 15 Gb gratis
  • Mega te da 50 Gb gratis
  • OfiCloud te da 25 Gb gratis
  • OneDrive te da 5 Gb gratis

Todos estos programas son muy útiles y cumplen muy bien su tarea (con la excepción de OfiCloudSync, el cual a algunas computadoras las vuelve increíblemente lentas, parece que utiliza todos los recursos de la computadora, así que debe ser ejecutado solamente en horas de descanso, para no entorpecer las tareas habituales).

Sin embargo, todos tienen un gran defecto, y es que copian todo el contenido de las carpetas. En nuestro caso, eso significa que copian también a los archivos .BAK, .FXP, .TMP, etc. Pero eso no es todo, nuestras aplicaciones normalmente constan de cientos de archivos (.PRG, .FRX, .FRT, .SCX, .SCT, .VCX, .VCT, .GIF, .JPG, .PNG, etc.) y estar transfiriendo esa gran cantidad de archivos es muy lento, demora mucho. No es práctico.

Por ese motivo el autor de este blog ha escrito un programa que crea un archivo .ZIP que contiene solamente el código fuente importante. Y luego, se les pide a los programas anteriormente mencionados que suban «a la nube» solamente a ese archivo .ZIP, y con esto se consigue que la tarea se realice muy rápido.

Pero eso no es todo, al momento de crear ese archivo .ZIP también el programa lo sube «a la nube» mediante FTP y de esta manera se tiene mucha mayor seguridad y tranquilidad.

Como nuestras aplicaciones tienen muchas versiones no se crea un solo archivo .ZIP para cada aplicación sino que se crea un archivo .ZIP por cada versión. Eso significa que cada vez que se ejecuta el programa COPIAR_FUENTES.EXE se crea un archivo .ZIP con un nombre distinto a los anteriormente creados.

Ejemplo:

Nuestra aplicación se llama SQL_CONTA.EXE y su formulario principal es el siguiente:

Captura 1. El formulario principal de SQL_CONTA.EXE

Y el número de versión se encuentra hacia arriba y a la izquierda:

Captura 2. El número de versión de la aplicación

Entonces, si un cliente nos llama porque encontró un problema o quiere una mejora, lo único que debemos pedirle es que nos diga cual es el número de «Versión del Sistema» y siempre podremos saber cual es el código fuente que corresponde a esa versión y actuar en consecuencia.

Creando las carpetas para los backups

Para simplificarnos la vida, lo más conveniente es tener una carpeta principal dentro de la cual se guardarán todos los backups de todas nuestras aplicaciones, algo como:

Captura 3. La carpeta BackupsCódigoFuente del disco duro local se sincroniza con una carpeta (que podría llamarse distinto) de Mega en el disco duro remoto

 

Captura 4. La carpeta BackupsCódigoFuente del disco duro local se sincroniza con una carpeta (que podría llamarse distinto) de OneDrive en el disco duro remoto

Haciendo como se explica en este artículo conseguimos que:

  1. En «la nube» solamente estén archivos .ZIP
  2. Que esos .ZIP solamente contengan archivos relevantes
  3. Que en «la nube» no haya basura
  4. Que la subida sea muy rápida, porque los .ZIP ocupan poco espacio
  5. Que sea muy fácil buscar y encontrar el .ZIP que nos interesa

Comentarios:

Si ocurre un desastre y se pierde el código fuente de nuestras aplicaciones que teníamos en una computadora, eso puede destrozarnos la vida. Por ese motivo es que debemos tener a buen resguardo nuestro código fuente y así poder recuperarlo en caso de necesidad.

Hay varios programas que nos permiten sincronizar carpetas de nuestro disco duro local con carpetas de un disco duro remoto y debemos aprovechar y usar tales programas. Todos ellos nos proveen de unos cuantos gigabytes gratis y eso suele ser más que suficiente para nuestras necesidades.

Sin embargo, tales programas copian los contenidos de carpetas completas y entonces podrían llegar a ser muy lentos porque esas carpetas pueden contener cientos y cientos de archivos. Lo más inteligente es crear un archivo .ZIP que contenga a todos los archivos que nos interesan, y nada más. Haciendo así se subirá «a la nube» solamente el archivo .ZIP y en consecuencia será muchísimo más rápido.

Artículos relacionados:

El índice del blog VFPavanzado

 

Protegiendo nuestras aplicaciones. Ofuscación (4)

Con lo visto en los tres artículos anteriores de esta serie seguramente ya tienes muy claro lo que es la ofuscación y lo útil que es para ayudarte a proteger tu código fuente.

Ahora veremos un punto muy relacionado: creando nombres inentendibles.

Para ello, haremos uso de la función RAND()

La función RAND() devuelve un número al azar entre 0 y 0.999999999999999

Bueno, eso de «al azar» no es del todo cierto.

La función RAND() para obtener los números que devolverá usa lo que se llama una «semilla». Y si la semilla es la misma…los números devueltos son exactamente los mismos.

Por ejemplo, si ingresas al Visual FoxPro y en la ventana de comandos escribes:

? RAND()

Esto es lo que verás:

Captura 1. El resultado de ejecutar a la función RAND()

Obtuviste el número 0.85, pero si ahora sales del Visual FoxPro, vuelves a entrar, y vuelves a escribir:

? RAND()

¡¡¡Obtendrás siempre el número 0.85!!!

¿Por qué eso?

Porque siempre, y en todos los casos, cuando se ingresa al Visual FoxPro se usa como «semilla» al número 100001

Y siempre, y en todos los casos, si la «semilla» es la misma, los números que devuelve la función RAND() son exactamente los mismos.

¿Cómo se elige la «semilla»?

Escribiéndola como argumento de la función RAND(), por ejemplo:

Listado 1. Estableciendo la «semilla» de la función RAND()

=RAND(876)
? RAND()
? RAND()
? RAND()

Si ejecutas el Listado 1. esto es lo que obtendrás:

Captura 2. El resultado de ejecutar el Listado 1.

Y siempre obtendrás los mismos resultados, sin importar la cantidad de veces que ejecutes al Listado 1. porque si la «semilla» es la misma, los números que devolverá la función RAND() serán los mismos. Además de la «semilla» 876 (que fue la usada en el Listado 1.) puedes usar cualquier otra «semilla» y verás que siempre obtendrás los mismos números.

¿Cómo se puede hacer para obtener números lo más al azar posibles?

Como ya sabes, si la «semilla» es la misma, los números que obtendrás serán los mismos. Sin embargo, hay un truco para que la «semilla» cambie cada vez, automáticamente. Y es poniendo un argumento negativo, porque si el argumento es negativo se usa como «semilla» al reloj del Windows. Como ese reloj tiene una precisión de 1 milisegundo eso significa que para que una secuencia de números se repita, se debería ejecutar la función RAND() a la misma hora, en el mismo minuto, en el mismo segundo, y en el mismo milisegundo. Lo cual, en la práctica, es imposible.

Listado 2. Poniendo como «semilla» de la función RAND() al reloj del Windows

=RAND(-1)
? RAND()
? RAND()
? RAND()

Si ejecutas al Listado 2. obtendrás un número que en la práctica, es totalmente al azar. Por ejemplo, podrías obtener:

Captura 3. El resultado de usar como «semilla» a un número negativo

Y si quieres, puedes salir del Visual FoxPro, volver a entrar, volver a ejecutar el Listado 2. y con toda seguridad, obtendrás una secuencia de números distinta.

Porque, como ya hemos visto, para que la secuencia se repita, también se debería repetir la hora, el minuto, el segundo, y el milisegundo en que se ejecutó la función RAND(-1).

Mostrando los números con mayor precisión

La función RAND() puede devolver un número que tiene 15 decimales, pero en los ejemplos anteriores solamente hemos visto 2 decimales, para verlos a los 15 escribiríamos así:

Listado 3. Viendo los números devueltos por la función RAND() con 15 decimales

SET DECIMALS TO 15

=RAND(-1)

? RAND()
? RAND()
? RAND()

Captura 4. Usando SET DECIMALS TO 15 antes de la función RAND()

Y puedes ejecutar al Listado 3. todas las veces que quieras y con toda seguridad que cada vez obtendrás números distintos.

El rango utilizable de la función RAND()

Cuando queremos obtener un número entero mediante la función RAND(), esta es la fórmula que debemos utilizar:

NumeroInicial + INT(RAND() * CantidadNumerosPosibles)

Donde NumeroInicial es el número más bajo que podríamos obtener y CantidadNumerosPosibles es la cantidad de números distintos que podríamos obtener.

Ejemplos:

* Un número entre 1 y 10, inclusives
? 1 + INT(RAND() * 10)

* Un número entre 1 y 20, inclusive
? 1 + INT(RAND() * 20)

* Un número entre 10 y 15, inclusives
? 10 + INT(RAND() * 6)

* Un número entre 20 y 30, inclusives
? 20 + INT(RAND() * 11)

Resumiendo:

La función RAND() devuelve un número entre 0 y 0.999999999999999. El número que devuelve depende de la «semilla» que se haya establecido. Al iniciar el Visual FoxPro esa «semilla» es siempre el número 100001. Para obtener números lo más al azar posibles debemos usar como «semilla» a un número negativo porque en ese caso se usará como «semilla» al reloj del Windows y como el reloj del Windows tiene una precisión de 1 milisegundo para que una secuencia de números se repita también debería repetirse la hora, el minuto, el segundo, y el milisegundo en que se ejecutó la función RAND(-1).

Creando una función que devuelva texto inentendible

Ahora que ya sabemos como usar a la función RAND() el siguiente paso será crear a una función que nos devuelva un texto sin sentido.

Esta función recibirá como argumento la cantidad de caracteres que deseamos que tenga el texto ilegible y devolverá a ese texto ilegible.

Listado 4. Una función que nos devuelve un texto ilegible

=Rand(-1)    && Para que elija números al azar

CLEAR

NOMBRE       = "tcNombreTabla"
NUEVO_NOMBRE = TEXTO_ILEGIBLE(40)

? NOMBRE
? NUEVO_NOMBRE

RETURN
*
*
FUNCTION TEXTO_ILEGIBLE
LPARAMETERS tnLongitud
LOCAL lcCaracteresValidos, lcTextoOfuscado, lnI, lnNumero, lcCaracterElegido
  
  *--- Los caracteres que pueden tener los nombres de las variables
  lcCaracteresValidos = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"
  
  *--- Las variables deben empezar con una letra o con un guión bajo, nunca con un dígito
  lnNumero        = 1 + Int(Rand() * 53)
  lcTextoOfuscado = Substr(lcCaracteresValidos, lnNumero, 1)

  FOR lnI = 2 TO tnLongitud
    lnNumero          = 1 + Int(Rand() * Len(lcCaracteresValidos))
    lcCaracterElegido = Substr(lcCaracteresValidos, lnNumero, 1)
    lcTextoOfuscado   = lcTextoOfuscado + lcCaracterElegido
  ENDFOR
  
RETURN (lcTextoOfuscado)
*
*

Cada vez que ejecutemos el Listado 4. obtendremos un texto distinto, y en todos los casos será un texto que no tendrá sentido. Por ejemplo:

Captura 5. Uno de los resultados posibles al ejecutar el Listado 4.

En el código fuente, nosotros veremos tcNombreTabla pero el «pirata» verá un chorizo inentendible, tal y como se muestra en la Captura 5.

Como los nombres de las variables no pueden empezar con un dígito, en la función TEXTO_ILEGIBLE() nos aseguramos que el primer carácter sea una letra o un guión bajo, y los siguientes caracteres ya pueden ser cualesquiera, no hay problemas.

¿Y por qué el número 40 como argumento de la función TEXTO_ILEGIBLE()?

Por dos motivos:

  1. Si hubiéramos puesto TEXTO_ILEGIBLE(1) el nombre devuelto tendría solamente 1 carácter y la probabilidad de que dos variables tuvieran el mismo nombre sería bastante alta. Si en tu código fuente legible tienes dos variables con distintos nombres, en tu código fuente ofuscado también debes tener dos variables con distintos nombres. Si tienen el mismo nombre, eso podría causar un desastre mayúsculo. Al enviar como argumento al número 40, la probabilidad de que dos variables compartan el mismo nombre en la práctica es cero.
  2. Para dificultarle la tarea al «pirata» porque ver nombres de variables de 40 caracteres ilegibles, le quita el ánimo de desofuscar hasta al más pintado.

Conclusión:

Ahora ya tenemos una función que nos devuelve un texto al azar y usaremos esa función para asignarles nombres a las variables que ofuscaremos.

Artículos relacionados:

Protegiendo nuestras aplicaciones. Ofuscación (1)

Protegiendo nuestras aplicaciones. Ofuscación (2)

Protegiendo nuestras aplicaciones. Ofuscación (3)

El índice del blog VFPavanzado

 

 

 

 

 

 

 

 

 

Protegiendo nuestras aplicaciones. Ofuscación (3)

En los dos artículos anteriores de esta serie:

Protegiendo nuestras aplicaciones. Ofuscación (1)

Protegiendo nuestras aplicaciones. Ofuscación (2)

ya hemos visto lo que es la ofuscación y como utilizarla para nuestro beneficio. En el último artículo mencionado obtuvimos el siguiente código fuente ofuscado:

Listado 1. El programa final para imprimir el salario del empleado

CLEAR
asjfhlajsdfga7ersdfaer=sfhskfhsadfyjdsf("MXDQ#SÌUH]",0)
uehtkdsjngksjdgtfagse33rsd=42
jisjhfjsa6r348yjfhbskdfs=12
ksjfhskgfjaeri4634fbvad=uehtkdsjngksjdgtfagse33rsd*jisjhfjsa6r348yjfhbskdfs
? sfhskfhsadfyjdsf("Ho#vdodulr#d#sdjdu#d#",0)+asjfhlajsdfga7ersdfaer+sfhskfhsadfyjdsf("#hv=#",0)+Transform(ksjfhskgfjaeri4634fbvad)+sfhskfhsadfyjdsf("#göoduhv",0)
FUNCTION sfhskfhsadfyjdsf
LPARAMETERS asdfjashdfjryajdfhf44, dfsfasfsdrxcvxe4z223
LOCAL ihskjf7f7xcc7sdfxsdfsd, ksdfjasdflkxuclvaldsfxasdr, xcvxcvasruxnvadfaf, sfdlu8r3409fjlskfl3223sf
ksdfjasdflkxuclvaldsfxasdr = ""
IF VarType(asdfjashdfjryajdfhf44) == "C" THEN
FOR ihskjf7f7xcc7sdfxsdfsd = 1 to Len(asdfjashdfjryajdfhf44)
xcvxcvasruxnvadfaf = SubStr(asdfjashdfjryajdfhf44, ihskjf7f7xcc7sdfxsdfsd, 1)
sfdlu8r3409fjlskfl3223sf = Chr((Asc(xcvxcvasruxnvadfaf) + iif(dfsfasfsdrxcvxe4z223 == 1, 3, -3)))
ksdfjasdflkxuclvaldsfxasdr = ksdfjasdflkxuclvaldsfxasdr + sfdlu8r3409fjlskfl3223sf
ENDFOR
ENDIF
RETURN (ksdfjasdflkxuclvaldsfxasdr)

Y viendo algo así, seguramente el 99,95% de los posibles «piratas» ya desistiría de la idea de «piratearte». Pero…supongamos que eres muy paranoico y quisieras ofuscar aún más a tu código fuente para aumentar el porcentaje anterior.

La cuestión por lo tanto es, ¿cómo se puede hacer para dificultarle al «pirata» la tarea de volver legible el código fuente de nuestra aplicación?

Para ello usaremos una técnica llamada: código adicional inútil.

La idea es muy simple: rellenar a nuestra aplicación con código que de nada sirve, solamente ocupa espacio allí, no hace algo útil. Pero…eso el «pirata» no lo sabe ni lo puede saber antes de desofuscar a nuestra aplicación.

Si ese código adicional inútil ocupa muchas líneas entonces es muy probable que se le vayan totalmente las ganas de desofuscar a nuestra aplicación. Veamos un ejemplo.

Listado 3. La función ENCRIPTAR()

FUNCTION ENCRIPTAR
LPARAMETERS tcTexto, tnForma
LOCAL lnI, lcNuevoTexto, lcCaracter, lcValor
  
  lcNuevoTexto = ""
  
  IF VarType(tcTexto) == "C" THEN
    FOR lnI = 1 to Len(tcTexto)
      lcCaracter = SubStr(tcTexto, lnI, 1)
      lcValor = Chr((Asc(lcCaracter) + iif(tnForma == 1, 3, -3)))
      lcNuevoTexto = lcNuevoTexto + lcValor
    ENDFOR
  ENDIF
  
RETURN (lcNuevoTexto)
*
*

En el Listado 3. vemos que las líneas útiles de la función ENCRIPTAR() son 12. No muchas, un «pirata» no se preocuparía si solamente son 12 las líneas que debe desofuscar. Pero si el código fuente fuera así:

Listado 4. La función ENCRIPTAR() con código adicional inútil

FUNCTION ENCRIPTAR
LPARAMETERS tcTexto, tnForma
LOCAL lnI, lcNuevoTexto, lcCaracter, lcValor, lcFill1, lcFill2, lnFill1, lnFill2, lnFill3
  
  lcNuevoTexto = ""
  lcFill1      = "NUEVO TEXTO"
  ldFill2      = "OTRO TEXTO"
  lnFill1      = 13
  
  IF VarType(tcTexto) == "C" THEN
    lnFill2 = 0
    lnFill3 = lnFill2 - lnFill1
    FOR lnI = 1 to Len(tcTexto)
      lnFill1 = lnFill1 + lnFill2 * lnFill3
      lcFill2 = ""
      lcCaracter = SubStr(tcTexto, lnI, 1)
      lcValor = Chr((Asc(lcCaracter) + iif(tnForma == 1, 3, -3))) + lcFill2
      lcNuevoTexto = lcNuevoTexto + lcValor
      lnFill3 = lnFill3 * 2
    ENDFOR
  ENDIF
  
RETURN (lcNuevoTexto)
*
*

hemos agregado 8 líneas con código adicional inútil. Como el «pirata» no ve nuestro código fuente legible sino nuestro código fuente ofuscado no puede saber si esas líneas son útiles o si son inútiles antes de desofuscar a toda nuestra función. Y si el código adicional inútil no ocupa 8 líneas como en el Listado 4. sino 30, 40, o más líneas, pues…muy pocas ganas tendrá de sentarse a desofuscar.

Las constantes o variables que usamos para agregar código adicional inútil, pueden ser de tipo carácter, de tipo numérico, de tipo fecha, de tipo boolean. La idea es que nuestra función sea mucho más larga de lo necesario para así hacerle la vida difícil al «pirata».

En mi caso, llamo a esas variables con el nombre «fill» (relleno, en inglés) para saber que son variables inútiles, que están de puro relleno, y así no confundirme con las variables verdaderas, las que sí son útiles. Pero tú puedes llamarlas como prefieras.

Escribiendo algo así:

Listado 5. Más código adicional inútil

lcFill1 = ""
lcFill2 = lcFill1
.
.
.
(varias líneas aquí)
.
.
lcFill1 = lcFill1 + lcFill1 + NVL(lcFill1, lcFill2)
.
.
.
lcMiVariableVerdadera = lcFill1 + lcMiVariableVerdadera + lcFill1 + lcFill2

En nada afectas a la función, pero sí afectas al cerebro del «pirata», a quien le puede dar un patatús por tener que desofuscar a tanto código inútil.

Conclusión:

Ofuscar no es solamente cambiar el nombre de una variable por otro nombre sin significado sino también escribir código adicional inútil.

Porque como recordarás, nuestra intención es complicarle la vida lo más posible a los «piratas».

O sea, tendremos éxito si conseguimos que desistan de la tarea de «piratearnos».

Artículos relacionados:

Protegiendo nuestras aplicaciones. Ofuscación (1)

Protegiendo nuestras aplicaciones. Ofuscación (2)

El índice del blog VFPavanzado

 

 

 

Protegiendo nuestras aplicaciones. Ofuscación (2)

Ya hemos visto lo que es la ofuscación, como puede resultarnos muy útil, y también que podría acarrearnos un problema muy serio si no somos cuidadosos.

Pero si hacemos las cosas bien, podríamos tener la certeza de que nadie «pirateará» nuestras aplicaciones.

En este artículo:

Protegiendo nuestras aplicaciones. Ofuscación (1)

vimos que ofuscar los nombres de las variables es un método de protección muy efectivo. Pero eso no es todo. Hay más.

Listado 1. El código fuente original

Nombre          = "JUAN PÉREZ"
HorasTrabajadas = 42
SalarioPorHora  = 12
SalarioTotal    = HorasTrabajadas * SalarioPorHora
? "El salario a pagar a " + Nombre + " es: " + Transform(SalarioTotal) + " dólares"

El código fuente que ves en el Listado 1. es muy fácil de entender, entonces para complicarle la vida al posible pirata lo ofuscamos y queda algo así:

Listado 2. El código fuente ofuscado

asjfhlajsdfga7ersdfaer="JUAN PÉREZ"
uehtkdsjngksjdgtfagse33rsd=42
jisjhfjsa6r348yjfhbskdfs=12
ksjfhskgfjaeri4634fbvad=uehtkdsjngksjdgtfagse33rsd*jisjhfjsa6r348yjfhbskdfs
? "El salario a pagar a "+asjfhlajsdfga7ersdfaer+" es: "+Transform(ksjfhskgfjaeri4634fbvad)+" dólares"

Y el código fuente es ahora mucho más difícil de entender…pero no excesivamente difícil. ¿Por qué? Porque hay texto legible en él. El pirata, viendo esta línea:

? "El salario a pagar a "+asjfhlajsdfga7ersdfaer+" es: "+Transform(ksjfhskgfjaeri4634fbvad)+" dólares"

rápidamente se dará cuenta que en la variable asjfhlajsdfga7ersdfaer se guarda el nombre de la persona y que en la variable ksjfhskgfjaeri4634fbvad se guarda el salario total que se le debe pagar a esa persona.

Entonces, tiene pistas muy valiosas que le ayudarán a descifrar el contenido de las demás variables.

Sin embargo, si nuestro programa ofuscador también ofusca el texto que está entrecomillado, podríamos obtener algo así:

Listado 3. El código fuente ofuscado incluyendo las constantes literales

asjfhlajsdfga7ersdfaer=sfhskfhsadfyjdsf("MXDQ#SÌUH]",0)
uehtkdsjngksjdgtfagse33rsd=42
jisjhfjsa6r348yjfhbskdfs=12
ksjfhskgfjaeri4634fbvad=uehtkdsjngksjdgtfagse33rsd*jisjhfjsa6r348yjfhbskdfs
? sfhskfhsadfyjdsf("Ho#vdodulr#d#sdjdu#d#",0)+asjfhlajsdfga7ersdfaer+sfhskfhsadfyjdsf("#hv=#",0)+Transform(ksjfhskgfjaeri4634fbvad)+sfhskfhsadfyjdsf("#göoduhv",0)

Lo cual le complicará sobremanera la vida al posible «pirata» porque no ve un texto legible que le pueda servir de ayuda, que le de alguna pista, para su tarea de volver legible a nuestro código fuente ofuscado.

Si comparas ahora el Listado 1. con el Listado 3. notarás claramente por qué la ofuscación es una técnica tan efectiva para proteger a nuestras aplicaciones de los «piratas».

En el Listado 3. es la función sfhskfhsadfyjdsf() la encargada de desencriptar al texto que se le envía como argumento.

En nuestro código fuente legible, escribiríamos algo así:

Nombre = ENCRIPTAR(MSG_921, 0)
.
.
? ENCRIPTAR(MSG_214, 0) + Nombre + ENCRIPTAR(MSG_345, 0) + Transform(SalarioTotal) + ENCRIPTAR(MSG_122, 0)

Cualquier función que te permita encriptar/desencriptar texto te servirá, por ejemplo la que se muestra a continuación:

Listado 4. La función ENCRIPTAR()

FUNCTION ENCRIPTAR
LPARAMETERS tcTexto, tnForma
LOCAL lnI, lcNuevoTexto, lcCaracter, lcValor
  
  lcNuevoTexto = ""
  
  IF VarType(tcTexto) == "C" THEN
    FOR lnI = 1 to Len(tcTexto)
      lcCaracter   = SubStr(tcTexto, lnI, 1)
      lcValor      = Chr((Asc(lcCaracter) + iif(tnForma == 1, 3, -3)))
      lcNuevoTexto = lcNuevoTexto + lcValor
    ENDFOR
  ENDIF
  
RETURN (lcNuevoTexto)
*
*

Esta es una función de encriptación súper sencilla, en la vida real por supuesto que utilizaríamos una más elaborada.

Para facilitarnos la vida, a los mensajes los guardamos dentro de un archivo de inclusión, tendríamos algo así:

Captura 1. El archivo que contiene las constantes literales

Pero al encriptar esos mensajes con la función mostrada en el Listado 4., obtendremos algo así:

Captura 2. El archivo de inclusión con las constantes definidas encriptadas

Las cuales son las constantes definidas que ves en el Listado 3.

Finalmente, nuestro programa quedaría así:

Listado 5. El programa final después de ser ofuscado

CLEAR
asjfhlajsdfga7ersdfaer=sfhskfhsadfyjdsf("MXDQ#SÌUH]",0)
uehtkdsjngksjdgtfagse33rsd=42
jisjhfjsa6r348yjfhbskdfs=12
ksjfhskgfjaeri4634fbvad=uehtkdsjngksjdgtfagse33rsd*jisjhfjsa6r348yjfhbskdfs
? sfhskfhsadfyjdsf("Ho#vdodulr#d#sdjdu#d#",0)+asjfhlajsdfga7ersdfaer+sfhskfhsadfyjdsf("#hv=#",0)+Transform(ksjfhskgfjaeri4634fbvad)+sfhskfhsadfyjdsf("#göoduhv",0)
FUNCTION sfhskfhsadfyjdsf
LPARAMETERS asdfjashdfjryajdfhf44, dfsfasfsdrxcvxe4z223
LOCAL ihskjf7f7xcc7sdfxsdfsd, ksdfjasdflkxuclvaldsfxasdr, xcvxcvasruxnvadfaf, sfdlu8r3409fjlskfl3223sf
ksdfjasdflkxuclvaldsfxasdr = ""
IF VarType(asdfjashdfjryajdfhf44) == "C" THEN
FOR ihskjf7f7xcc7sdfxsdfsd = 1 to Len(asdfjashdfjryajdfhf44)
xcvxcvasruxnvadfaf = SubStr(asdfjashdfjryajdfhf44, ihskjf7f7xcc7sdfxsdfsd, 1)
sfdlu8r3409fjlskfl3223sf = Chr((Asc(xcvxcvasruxnvadfaf) + iif(dfsfasfsdrxcvxe4z223 == 1, 3, -3)))
ksdfjasdflkxuclvaldsfxasdr = ksdfjasdflkxuclvaldsfxasdr + sfdlu8r3409fjlskfl3223sf
ENDFOR
ENDIF
RETURN (ksdfjasdflkxuclvaldsfxasdr)

Y si lo ejecutamos, esto será lo que obtendremos:

Captura 3. El resultado de ejecutar el programa del Listado 5.

Que es exactamente igual a lo que obtendremos si ejecutamos el programa mostrado en el Listado 1., o sea que para el usuario no hay diferencia, son idénticos, pero para el pirata que curiosea en nuestro código fuente…

 

Entonces, ¿qué es lo mejor de la ofuscación?

Que nuestro programa compila, el usuario no notará la diferencia, no necesitaremos del ReFox o del MoleBox o de algún otro programa para protegerlo y podremos dormir tranquilos: nadie nos pirateará.

O acaso ¿tú tratarías de piratear un programa ofuscado de la forma en que se mostró en este artículo?

Conclusión:

Todo programa hecho con Visual FoxPro se puede descompilar. Sabiendo eso, si queremos proteger a nuestro código fuente, lo más inteligente es ofuscarlo, porque así le quitaremos las ganas hasta al más pintado de intentar «piratearlo». Le resultará muchísimo más rápido y muchísimo más barato desarrollar una nueva aplicación similar a la nuestra que «piratear» nuestra aplicación.

Y ahora, ¿crees que ya sabes todo sobre la ofuscación?

Pues no, no es así, aún hay más, como veremos en el siguiente artículo.

Artículos relacionados:

Protegiendo a nuestras aplicaciones. Ofuscación (1)

El índice del blog VFPavanzado

 

Protegiendo nuestras aplicaciones. Ofuscación (1)

Una preocupación o al menos motivo para meditar el tema, de muchos programadores es ¿cómo proteger la aplicación para que no sea «pirateada»?

Si invertimos mucho tiempo en el desarrollo de una aplicación no queremos que alguien se apropie gratuitamente de nuestro trabajo y lucre con él.

Por eso, con el transcurrir de los años fueron apareciendo aplicaciones para proteger a otras aplicaciones de ser descompiladas y por lo tanto, desprotegidas.

Descompilar una aplicación significa volver legible a su código fuente. Y si otro programador ve nuestro código fuente, entonces podría modificarlo a su gusto, para quitarle cualquier protección que le hubiéramos puesto. Y ya podría venderla como si fuera suya.

La más famosa de las aplicaciones que se usan para descompilar los programas .EXE compilados con Visual FoxPro se llama ReFox.

Es un programa muy bueno, si tienes un .EXE creado con Visual FoxPro y quieres ver su código fuente, le pasas el ReFox y listo, ya lo has conseguido.

Hay varios programas que puedes utilizar para proteger a tu código fuente, además del ya mencionado ReFox también podrías usar el MoleBox y varios otros. Esos programas dificultan en gran medida la descompilación, pero ningún programa puede evitarla con un 100% de seguridad. Hagas lo que hagas, siempre alguien conseguirá descompilar tu .EXE y ver su código fuente (si tiene los conocimientos, el tiempo, y el interés suficiente para dedicarse a esa tarea, claro).

Entonces, sabiendo que no podrás evitar la descompilación ¿tienes alguna otra manera de proteger tu código fuente?

Sí, esa manera existe y se llama ofuscación.

¿Qué es la ofuscación?

Es convertir un código fuente legible en un código fuente casi ilegible.

¿Cómo se ofusca un código fuente?

Reemplazando los nombres originales de las variables por nombres que no tienen significado.

Ejemplo 1:

Antes de ofuscarlo, nuestro código fuente se ve así:

CantidadVendida =  12
PrecioUnitario  = 500

TotalVenta = CantidadVendida * PrecioUnitario

Este código fuente es fácilmente legible y cualquier programador te podrá decir lo que hace. Es muy entendible.

Pero si lo ofuscamos, podría quedar algo así:

lsjdfhaljksdfhjasfhJUHj=12
ijkrmgñiuieekfjasdNubz=500
sjref7ekrnwe8uewkllaiskdfkea=lsjdfhaljksdfhjasfhJUHj*ijkrmgñiuieekfjasdNubz

Para el Visual FoxPro no hay problema, él compilará perfectamente bien ambos códigos fuente. El resultado que se obtendrá será exactamente el mismo. Ninguna diferencia.

Pero para los seres humanos sí que hay una gran diferencia. Mientras que el código fuente original cualquiera lo puede entender, el código fuente ofuscado es otra historia, ya no es fácil entenderlo.

Si con solamente 3 variables ya se te quitaron las ganas de entender ese código fuente. ¿Te imaginas si todas las variables están ofuscadas?

Realmente, la probabilidad de que alguien quiera dedicarse a la tarea de desofuscar un código fuente ofuscado, en la práctica, es cero.

Y así, de esa manera, puedes estar bien tranquilo y bien seguro. Si tu código fuente está ofuscado ¿qué importa que le pasen el ReFox a tu .EXE?

Que lo hagan.

No entenderán un pepino y no les servirá de nada.

¿Que debemos ofuscar?

Todo lo que nosotros escribimos y que funcionará igual aunque se le cambie el nombre. Es decir:

  • Nombres de variables
  • Nombres de constantes declaradas
  • Nombres de PROCEDURE
  • Nombres de FUNCTION
  • Nombres de clases
  • Nombres de propiedades
  • Nombres de métodos

Y también deberemos borrar todos y cada uno de los comentarios que hayamos escrito.

Lo que jamás debemos ofuscar, o nuestro programa se quedará inservible son: nombres de comandos del VFP, nombres de funciones del VFP, nombres de instrucciones del VFP, etc.

Ejemplo 2:

En el primer artículo de este blog dedicado al uso de ReportListener puedes encontrar el siguiente código fuente:

LOCAL loRL
  
  loRL = CreateObject("BarrasVerdes")
  
  loRL.ListenerType = 1
  
  USE CUENTAS
  
  REPORT FORM INFORME1 OBJECT loRL
  
RETURN
*
*
DEFINE CLASS BarrasVerdes AS ReportListener
  
  nFila = 0

  PROCEDURE BeforeBand(tnBandObjCode, tnFRXRecno)
    THIS.nFila = THIS.nFila + 1
  ENDPROC
  *
  *
  PROCEDURE EvaluateContents(tnFRXRecno, toProps)
    *-- tnFRXRecno: número del registro en el archivo .FRX
    *-- toProps   : propiedades del objeto
    WITH toProps
      .Reload = .T.
      IF This.nFila % 2 = 0 THEN     && Si es una fila par
        .FillRed   =   0
        .FillGreen = 255
        .FillBlue  =   0
        .FillAlpha = 128
      ENDIF
    ENDWITH
  ENDPROC
  *
  *
ENDDEFINE
*
*

Y si lees ese artículo del blog, te resultará muy fácil entender lo que hace este programita. Es muy sencillo.

Pero si lo ofuscamos, podría quedar algo así:

LOCAL HFAGKFHGAKYER343434HDFD
HFAGKFHGAKYER343434HDFD=CreateObject("SKDFKJJEYRFSJDGFIERDR4")
HFAGKFHGAKYER343434HDFD.ListenerType=1
USE CUENTAS
REPORT FORM INFORME1 OBJECT HFAGKFHGAKYER343434HDFD
RETURN
DEFINE CLASS SKDFKJJEYRFSJDGFIERDR4 AS ReportListener
SDHFKJHKJY4444SDFAY3FDFS=0
PROCEDURE BeforeBand(UWEYIR7W3IJ4BBKJSGIUGI3434,ALJSDHFAUEYRLUABSVJY434SDJHFD)
THIS.SDHFKJHKJY4444SDFAY3FDFS=THIS.SDHFKJHKJY4444SDFAY3FDFS+1
ENDPROC
PROCEDURE EvaluateContents(ALJSDHFAUEYRLUABSVJY434SDJHFD,HDGFJSHGERJGFJHSGJDGRJHGJGHJGJ3443XA)
WITH HDGFJSHGERJGFJHSGJDGRJHGJGHJGJ3443XA
.Reload=.T.
IF This.SDHFKJHKJY4444SDFAY3FDFS%2=0 THEN
.FillRed=0
.FillGreen=255
.FillBlue=0
.FillAlpha=128
ENDIF
ENDWITH
ENDPROC
ENDDEFINE

Como ya sabes, para el Visual FoxPro ambos programas son idénticos. Compilarán exactamente igual y funcionarán exactamente igual. Ninguna diferencia hay entre ellos.

Pero para los seres humanos evidentemente que hay muchísima diferencia. Mientras que uno de ellos es legible, el otro es muy difícil de leer y de entender.

¿Cuál es el gran problema que puedes tener si ofuscas tu código fuente?

Que si no tienes guardado tu código fuente original, el que es legible, el gran y principal perjudicado de la ofuscación…serás tú.

Así que ¡¡¡mucho cuidado!!!

Nunca ofusques antes de asegurarte que tu código fuente original, legible, tiene backups actualizados y que funcionan.

La metodología de ofuscación

Desde luego que podrías hacer la ofuscación manualmente, a cada variable la reemplazas por un nombre raro y listo. Pero eso no es práctico, demorarás muchas horas y además es propenso a errores. Lo correcto es que tengas un programa ofuscador, un programa que se dedique a la tarea de ofuscar.  Será mucho más rápido y mucho más seguro de que no «meterás la pata» ofuscando lo que no deberías ofuscar.

Para evitar el problema de ofuscar lo que no deberías ofuscar, lo correcto es hacer la ofuscación de la siguiente manera:

  1. Creas una carpeta donde se guardará tu código ofuscado
  2. Tu programa ofuscador copia los .PRG y los formularios originales a esa carpeta
  3. Ofusca los .PRG y los formularios que se encuentran en esa carpeta

Entonces:

  • En una carpeta estará tu código fuente original, legible
  • En la otra carpeta, estará tu código fuente ofuscado
  • Compilas el código fuente ofuscado

Y como en tu .EXE estará el código fuente ofuscado ¿alguien lo quiere descompilar? Puedes reírte pensando en la cara que pondrá cuando vea el código fuente de tu .EXE

Conclusión:

Es imposible evitar que descompilen un .EXE compilado con el Visual FoxPro pero lo que sí es posible es ofuscar el código fuente para que en la práctica se convierta en algo totalmente ilegible.

Esta es una protección casi, casi, casi, 100% segura.

En otro artículo veremos como crear un programa que tenga la tarea de ofuscar códigos fuente.

Artículos relacionados:

Mejorando los informes: ReportListener (1)

El índice del blog VFPavanzado

 

Usando códigos QR en nuestras aplicaciones (3)

En estos dos artículos:

Usando códigos QR en nuestras aplicaciones

Usando códigos QR en nuestras aplicaciones (2)

ya hemos visto como crear, imprimir, y leer, a los códigos QR. Entonces quizás te estés preguntando: ¿y para qué me servirían, en qué podría usarlos? Ahora, veremos algunas de las posibilidades. Solamente algunas, porque muchas más se te podrían ocurrir.

  • Banners publicitarios
  • Botellas y latas
  • Carpas de publicidad
  • Carteles
  • Diarios y revistas
  • Documentos
  • Entradas a eventos
  • Envases de alimentos
  • Etiquetas y calcomanías
  • Exhibidores
  • Folletos
  • Libros
  • Paquetes
  • Sitios web
  • Tarjetas de negocios
  • Vehículos
  • Vestimenta
  • Vidrieras
  • Volantes

Banners publicitarios

Captura 1. Un banner publicitario con un código QR

Botellas y latas

Captura 2. Una lata con un código QR

Carpas de publicidad

Captura 3. Publicidad sobre la mesa de un restaurante

Folletos

Captura 4. Un código QR en un folleto publicitario

Tarjetas de negocios

Captura 5 . Una tarjeta personal de negocios con un código QR

Captura 6. Un código QR en una prenda de vestir

Captura 7. Código QR en un cartel de ventas

Captura 8. Un código QR en un volante publicitario

Captura 9. En el envase del alimento un código QR para mostrar recetas

Captura 10. Código QR en una etiqueta

Conclusión:

Como has podido ver en las imágenes, se les puede dar una gran utilidad a los códigos QR, y ya dependerá de la creatividad de cada quien aplicarlos de una manera atractiva y beneficiosa.

Algunos ejemplos de lo que podría contener un código QR son:

  • Tarjeta personal o de identificación. Nombres, apellidos, profesión, teléfono celular, e-mail
  • Etiquetas de productos. País de procedencia, ingredientes, recetas, información nutricional
  • Avisos de conferencias. Fecha de la conferencia, tema de la conferencia, nombre del conferencista
  • Prendas de vestir. Material, país de procedencia, recomendaciones para el lavado, recomendaciones para el planchado
  • Carteles para la ventas de casas. Cantidad de habitaciones, cantidad de baños, características de la vivienda, precio de venta

Como en un código QR se pueden introducir hasta 4296 caracteres, hay muchísimas posibilidades más. Por eso, son cada vez más ampliamente usados.

Artículos relacionados:

Usando códigos QR en nuestras aplicaciones 

Usando códigos QR en nuestras aplicaciones (2)

El índice del blog VFPavanzado

 

Usando códigos QR en nuestras aplicaciones (2)

Ya habíamos visto en el artículo:

Usando códigos QR en nuestras aplicaciones

como podemos crear, imprimir, y leer códigos QR. Sin embargo, el método mostrado en ese artículo tiene un pequeño problema: la longitud máxima de los caracteres a codificar es de 255. O sea, no podemos codificar más que 255 caracteres. En la mayoría de los casos, 255 caracteres es más que suficiente, pero si alguna vez necesitas más caracteres entonces podrías utilizar el método que veremos ahora.

Usando la API de Google

Google pone a disposición de los programadores varias utilidades, algunas gratuitas y algunas de pago. Afortunadamente la que usaremos es gratuita.

Lo que haremos será decirle a don Google que cree para nosotros un archivo de imagen que contenga un código QR y luego descargaremos en nuestro disco duro ese archivo de imagen, para poder utilizarlo.

Listado 1. Creando un archivo de imagen que contiene un código QR usando Google

LOCAL lcMiTextoLargo, lcMiArchivoImagen, lcTamanoImagen, llArchivoCreado

  #DEFINE KEY_ENTER 13

  lcMiTextoLargo = "Este texto tiene más de 255 caracteres, para verificar que funciona cuando el código QR tiene más de 255 caracteres. "
  lcMiTextoLargo = lcMiTextoLargo + lcMiTextoLargo + lcMiTextoLargo + lcMiTextoLargo + lcMiTextoLargo + lcMiTextoLargo + lcMiTextoLargo

  lcMiTextoLargo = lcMiTextoLargo + " AQUÍ TERMINA EL TEXTO LARGO."

  lcMiArchivoImagen = Sys(5) + Curdir() + "ImagenQR.PNG"

  lcTamanoImagen = "400x400"

  llArchivoCreado = CREAR_IMAGEN_QR(lcMiTextoLargo, lcMiArchivoImagen, lcTamanoImagen)

  IF llArchivoCreado THEN
    =MessageBox("El archivo de imagen QR: " + Chr(KEY_ENTER) + Chr(KEY_ENTER) + lcMiArchivoImagen + Chr(KEY_ENTER) + Chr(KEY_ENTER) + "fue creado exitosamente")
  ELSE
    =MessageBox("No pude crear el archivo de imagen QR:" + Chr(KEY_ENTER) + lcMiArchivoImagen)
  ENDIF

RETURN
*
*
FUNCTION CREAR_IMAGEN_QR
LPARAMETERS tcTexto, tcNombreArchivoQR, tcTamanoImagen
LOCAL lcURLGoogle, lcTamano, lcTipoArchivo, lcTextoEnQR, llResultadoOK

  DECLARE LONG URLDownloadToFile IN URLMON;
          LONG pCaller,;
        STRING szURL,;
        STRING szFileName,;
          LONG dwReserved,;
          LONG lpfnCB

  lcURLGoogle   = "https://chart.googleapis.com/chart?"
  lcTamano      = "chs=" + tcTamanoImagen
  lcTipoArchivo = "cht=qr"
  lcTextoEnQR   = "chl=" + CONVERTIR_A_TEXTO_SEGURO(tcTexto)

  lcURLCompleta = lcURLGoogle + lcTamano + "&" + lcTipoArchivo + "&" + lcTextoEnQR

  llResultadoOK = URLDownloadToFile (0, lcURLCompleta, tcNombreArchivoQR, 0, 0) = 0

  RETURN(llResultadoOK)

ENDFUNC
*
*
FUNCTION CONVERTIR_A_TEXTO_SEGURO
LPARAMETERS tcTexto

  tcTexto = Strtran(tcTexto, " ", "%20")
  tcTexto = Strtran(tcTexto, "á", "a")
  tcTexto = Strtran(tcTexto, "é", "e")
  tcTexto = Strtran(tcTexto, "í", "i")
  tcTexto = Strtran(tcTexto, "ó", "o")
  tcTexto = Strtran(tcTexto, "ú", "u")
  tcTexto = Strtran(tcTexto, "ñ", "nh")
  tcTexto = Strtran(tcTexto, "Á", "A")
  tcTexto = Strtran(tcTexto, "É", "E")
  tcTexto = Strtran(tcTexto, "Í", "I")
  tcTexto = Strtran(tcTexto, "Ó", "O")
  tcTexto = Strtran(tcTexto, "Ú", "U")
  tcTexto = Strtran(tcTexto, "Ñ", "NH")
  tcTexto = Strtran(tcTexto, "&", "%26")
  tcTexto = Strtran(tcTexto, "¿", "%20")
  tcTexto = Strtran(tcTexto, "¡", "%20")

  RETURN(tcTexto)

ENDFUNC
*
*

En la primera parte del Listado 1. lo que hacemos es verificar que la creación del archivo de imagen se realice correctamente. Las importantes son las dos funciones: CREAR_IMAGEN_QR() y CONVERTIR_A_TEXTO_SEGURO().

La función CREAR_IMAGEN_QR() recibe tres parámetros:

  1. El texto que queremos codificar
  2. El nombre que tendrá en nuestro disco duro el archivo de imagen que se creará
  3. El tamaño (medido en pixeles) que tendrá ese archivo de imagen. Puedes elegir cualquier tamaño que quieras, pero siempre debe ser un cuadrado. Ejemplos: 200×200, 240×240, 300×300, 360×360

Para crear el archivo de imagen, la función CREAR_IMAGEN_QR() genera una URL que llama a una API de Google, la encargada de crear archivos de imagen QR y luego descarga en nuestro disco duro el archivo generado.

La función encargada de realizar esa tarea se llama URLDownloadToFile() y esta función devuelve un número al finalizar su ejecución. Si el número devuelto es cero significa que todo estuvo ok, cualquier otro número indicará que ocurrió un error.

La función CREAR_IMAGEN_QR() comparará ese número devuelto con cero, y si es cero entonces devolverá .T., de lo contrario devolverá .F.

La función CONVERTIR_A_TEXTO_SEGURO() recibe como parámetro el texto que se desea convertir y devuelve ese texto con los caracteres que pueden ser problemáticos convertidos a caracteres que funcionan bien.

¿Por qué esto?

Porque en las URL se usan los códigos ASCII entre 32 y 127 y cualquier carácter que esté fuera de ese rango puede llegar a causar problemas, por lo tanto hay que evitar que en una URL haya códigos ASCII fuera de rango. De eso justamente se encarga la función CONVERTIR_A_TEXTO_SEGURO().

Ventaja de este método

El código QR puede tener hasta 4296 caracteres.

Desventajas de este método

  1. Requiere una conexión a Internet
  2. Es más lento que el método que vimos en el artículo anterior
  3. No se pueden tener eñes ni letras acentuadas ni otros caracteres especiales, solamente texto ASCII estándar

Ejemplo práctico

Si copias y pegas el contenido del Listado 1. en un archivo .PRG y tienes conexión a Internet y  ejecutas ese archivo .PRG entonces se creará en tu disco duro un archivo llamado ImagenQR.PNG

Captura 1. El archivo de imagen que contiene el código QR

Y si ahora escaneas esa imagen con alguna aplicación que sirva para escanear códigos QR (como por ejemplo: QR & Barcode Scanner) entonces verás algo como esto:

Captura 2. El código QR después de haber sido escaneado

NOTA: Como el texto es muy largo, en la Captura 2. solamente vemos las últimas líneas de ese texto.

Conclusión:

En la mayoría de los casos, no necesitaremos que nuestros códigos QR tengan más de 255 caracteres y entonces podremos usar el método que ya vimos en el artículo anterior. Pero para cuando necesitemos más de 255 caracteres entonces allí sí se justificaría usar el método que hemos visto en este artículo.

Como ya sabes, las desventajas son que necesitas una conexión a Internet, que la creación del archivo de imagen es más lenta, y que no podrás tener letras eñes ni vocales acentuadas.

Artículos relacionados:

Usando códigos QR en nuestras aplicaciones (1)

Usando códigos QR en nuestras aplicaciones (3)

El índice del blog VFPavanzado

Usando códigos QR en nuestras aplicaciones

Los códigos QR se han vuelto muy populares y por eso es importante que sepamos como usarlos en nuestras aplicaciones, porque pueden darles un muy buen valor agregado.

¿Qué es un código QR?

Es un código que nos permite almacenar muchos datos y luego obtener esos datos muy rápido. QR son las iniciales de Quick Response, o en castellano: respuesta rápida.

El código QR es una versión mejorada de los muy conocidos códigos de barra. Pero mientras que los códigos de barra son uni-dimensionales, los códigos QR son bi-dimensionales, o sea que tienen dos dimensiones. Y por lo tanto, pueden guardar muchos más datos.

¿Cuáles son las capacidades de los códigos QR?

En un código QR se pueden guardar:

  • Numérico: hasta 7089 dígitos, o
  • Alfanumérico: hasta 4296 caracteres, o
  • Binario: hasta 2953 bytes

¿Cuál es la estructura de un código QR?

Para que el lector de códigos QR pueda saber que está leyendo un código QR éstos códigos tienen un formato o estructura pre-definidos. Ese formato es el siguiente:

  • 3 cuadrados grandes en las esquinas, para indicar que se trata de un código QR
  • Uno o varios cuadrados pequeños para indicar el alineamiento de los datos

Captura 1. Significado del código QR

La parte grisada superior y a la izquierda del código QR es muy importante, porque sirve para detectar y también para corregir errores de lectura. El resto de la parte grisada son los datos guardados.

¿Cómo crear un código QR?

Nuestras aplicaciones pueden necesitar dos cosas:

a) Crear un código QR

b) Leer un código QR

Veamos ahora como crear un código QR.

Aunque podríamos hacerlo desde cero, lo más recomendable es utilizar una clase que ya otra persona desarrolló, probó, verificó, y corrigió. En este artículo usaremos la clase FoxBarCodeQR, de L.María Guayán quien se basó en el archivo BarCodeLibrary.DLL de Darío Alvarez Aranda.

Listado 1. Creando un código QR

LOCAL lcMiTexto, lcMiArchivoImagen, loQR, lcQR_Imagen

  lcMiTexto = "BEMA01#BENITEZ#MARÍA#bmaria@hotmail.com#0981-234567#ASUNCIÓN#PARAGUAY#"

  lcMiArchivoImagen = Sys(5) + Curdir() + "MiImagenQR.PNG"

  SET PROCEDURE TO FOXBARCODEQR ADDITIVE

  loQR = CreateObject("FoxBarCodeQR")

  lcQR_Imagen = loQR.QRBarCodeImage(lcMiTexto, lcMiArchivoImagen, 6, 2)

  SET PROCEDURE TO

RETURN
*
*

En el Listado 1. vemos un pequeño programita que crea un archivo de imagen conteniendo el código QR pedido. La imagen generada es la siguiente:

Captura 2. El código QR que corresponde al archivo generado por el Listado 1.

Desglosemos el Listado 1.:

  • lcMiTexto contiene el texto que deseamos guardar en el código QR. Puede ser cualquier texto que se nos ocurra. Se usó el símbolo de numeral como separador (#) para saber donde termina cada campo, pero eso no sería necesario si el tamaño de cada campo será fijo
  • lcMiArchivoImagen guarda la ruta y el nombre del archivo de imagen. Importante: hay que guardar la ruta también, no solamente el nombre del archivo
  • SET PROCEDURE TO FoxBarCodeQR ADDITIVE nos permite utilizar todos los procedimientos y todas las funciones que se encuentran en el archivo FoxBarCodeQR.PRG
  • loQR es la variable que contendrá al objeto creado
  • lcQR_Imagen es la variable donde se guardará el archivo de imagen creado
  • QRBarCodeImage es el método que debemos ejecutar para crear el archivo gráfico que contiene al código QR. Sus parámetros son: a) el texto que deseamos guardar en el código QR, b) la ruta y el nombre del archivo de imagen, c) un número entre 2 y 12 que indica el tamaño que tendrá el archivo de imagen, y d) el tipo del archivo de imagen que es un número entre 0 y 2 (0=BMP, 1=JPG, 2=PNG)

Los tamaños de los archivos de imagen pueden ser (en pixeles):

  • 2 = 66 x 66
  • 3 = 99 x 99
  • 4 = 132 x 132
  • 5 = 165 x 165
  • 6 = 198 x 198
  • 7 = 231 x 231
  • 8 = 264 x 264
  • 9 = 297 x 297
  • 10 = 330 x 330
  • 11 = 363 x 363
  • 12 = 396 x 396

Como ves, siempre son cuadrados, y se van incrementando de 33 en 33.

¿Cómo insertar en un informe un código QR?

Insertar una imagen en un formulario supongo que lo sabes hacer, y por lo tanto no te mostraré eso. Pero veamos como insertar un código QR en un reporte. Lo único que debes hacer es insertar un control imagen y luego:

Captura 3. Insertando una imagen que se encuentra en el disco duro

En la Captura 3. vemos el caso cuando queremos insertar una imagen que se encuentra guardada en nuestro disco duro (o pen-drive, CD, DVD, etc.)

Captura 4. El código QR insertado en nuestro informe, usando un archivo de imagen

¿Y si queremos imprimir un código QR que depende de los datos de una tabla?

En ese caso nuestro programa variará un poco, y también variará nuestro reporte.

Listado 2. Creando un código QR con datos provenientes de una tabla

PRIVATE poQR, pcMiArchivoImagen

  SET PROCEDURE TO FOXBARCODEQR ADDITIVE

  poQR = CreateObject("FoxBarCodeQR")

  pcMiArchivoImagen = Sys(5) + Curdir() + "MiArchivoImagen"

  SET PROCEDURE TO

  USE PRODUCTOS

  REPORT FORM QR02 PREVIEW

  USE

RETURN
*
*

En la tabla de PRODUCTOS tenemos los registros que queremos codificar. Y además, si te fijas, verás que las variables ahora son PRIVATE, ya no son LOCAL, ¿por qué? porque tendremos que usarlas en nuestro reporte.

Captura 5. Un reporte para mostrar los códigos QR de los productos

 

Captura 6. Mostrando el contenido de Control Source

Y al ejecutar el Listado 2. veremos esto:

Captura 7. Mostrando cada producto con su respectivo código QR

O sea, estamos viendo a cada producto con su respectivo código QR. ¡¡¡Genial!!!

Ok, ya sabemos como crear un archivo de imagen que contiene un código QR y también sabemos como insertar esa imagen en un reporte. Ahora nos está faltando otro aspecto, muy importante: leer ese código QR para usarlo en nuestra aplicación.

¿Cómo leer un código QR?

Los códigos QR normalmente son escaneados usando un teléfono celular (móvil) para hacerlo. Por eso, no tiene mucho sentido que nuestro programa en Visual FoxPro se encargue de decodificar un código QR. Entonces, mejor le dejamos esa tarea a nuestro teléfono celular.

Hay muchas aplicaciones, inclusive gratuitas, que nos permiten decodificar un código QR (o sea, volver legible su contenido). La preferida por el autor de este blog se llama «QR & Barcode Scanner«. ¿Y por qué es la preferida? Porque es muy rápida y funciona perfectamente bien.

Entonces, debemos descargar e instalar en nuestro teléfono celular una aplicación que nos permita leer códigos QR (por ejemplo, puedes usar a QR & Barcode Scanner). A continuación simplemente apuntas a un código QR y listo. Ya el contenido del código QR se habrá vuelto legible.

Captura 8. El código QR escaneado y legible

Si observas la Captura 8. notarás que en la parte superior muestra en forma legible al contenido del código QR que escaneó. ¿Y cómo podemos usar a ese texto legible en nuestras aplicaciones? Pues si te fijas en la parte inferior de la imagen verás un mensaje que dice: ¡copiado al portapapeles!

Entonces ahora ya es todo muy fácil. Con cualquier programita hecho en Java, o JavaScript, o TypeScript, o el lenguaje que prefieras, lees el contenido del portapapeles del celular y lo usas como quieras usarlo. Simple y sencillo.

Conclusión:

Los códigos QR se están volviendo cada día más y más populares, es por lo tanto muy importante que sepamos como usarlos en nuestras aplicaciones. En este artículo se mostró:

  1. Como crear un código QR
  2. Como imprimir un código QR
  3. Como leer un código QR

Así que ya tienes una nueva característica que puedes agregar a tus aplicaciones.

La cantidad de usos que les puedes dar es impresionantemente grande porque como permiten guardar muchos caracteres se le pueden encontrar muchos usos, algunos de ellos son: identificar personas, identificar productos, ingresar a sitios web, hacer compras por Internet, ayudar a enfermos, y un largo etcétera.

Descargas:

Puedes descargar todos los archivos desde:

http://www.mediafire.com/file/azbnhh37pb41jq1/CODIGOS_QR.ZIP/file

Artículos relacionados:

Usando códigos QR en nuestras aplicaciones (2)

Usando códigos QR en nuestras aplicaciones (3)

El índice del blog VFPavanzado

 

De DBF a SQL (23). Usando la función CAST()

En SQL existe una función muy útil llamada CAST(). Se utiliza para cambiar el tipo de una variable o columna por otro tipo.

Por ejemplo, en Visual FoxPro para cambiar a una variable que es de tipo carácter por otra que es de tipo numérico podemos usar la función VAL().

Listado 1. Convirtiendo una variable de carácter a numérica en Visual FoxPro

? VAL("9")

Y el resultado, como ya sabes, será el número 9.

Todo está muy bien, pero con CAST() podemos hacer mucho más que eso:

Listado 2. Convirtiendo de carácter a numérico con CAST()

? CAST("9" AS INTEGER)

En el Listado 2. convertimos de carácter a numérico, sería el equivalente a usar la función VAL(), pero también podríamos escribir:

Listado 3. Convirtiendo de carácter a numérico con decimales

? CAST("9" AS NUMERIC(10, 2))

Aquí, el resultado no será 9 sino que será 9.00, o sea un 9 con dos decimales.

También podrías escribir algo como:

Listado 4. Convirtiendo de carácter a numérico de punto flotante

? CAST("9.123" AS FLOAT(10,2))

Devolverá 9.12 porque se le pidieron 2 decimales. También puedes hacer a la inversa, por ejemplo:

Listado 5. Convirtiendo de numérico a carácter

? CAST(123 AS CHARACTER(10))

Convertirá el número 123 al string «123». Fíjate que es importante la cantidad de caracteres que especifiques en la función CAST(). En este ejemplo pusimos 10, siempre debe ser igual o mayor a la cantidad de dígitos para que no se trunque el resultado.

También podemos convertir un carácter a fecha, por ejemplo:

Listado 6. Convirtiendo de carácter a fecha

SET DATE BRITISH
SET CENTURY ON

? CAST("21/04/2018" AS DATE)

Y desde luego, también puedes convertir de fecha a carácter, por ejemplo:

Listado 7. Convirtiendo de fecha a carácter

? CAST(Date() AS CHARACTER(10))

Nuevamente, hay que asegurarse de que la cantidad de caracteres sea suficiente para recibir a la fecha o se obtendrá un resultado truncado.

Conclusión:

En Visual FoxPro usamos varias funciones para convertir de un tipo de datos a otro tipo de datos, en SQL solamente usamos la función CAST(), eso nos facilita recordar cual es la función que debemos usar y también nos facilita la lectura de nuestro código fuente porque es más fácil que te olvides lo que hace:

? VAL(«123456»)

a que te olvides lo que hace:

? CAST(«123» AS INTEGER)

«CAST» significa «moldear» y «AS INTEGER» se traduce: «como entero». Si lees inglés, entonces es muy fácil saber que escribiste: «moldear a 123 como entero». Y por lo tanto, entender tu código fuente es más sencillo que escribir VAL().

NOTA: En nuestros ejemplos usamos solamente algunos tipos de datos, hay más tipos de datos que puedes usar: LOGICAL, DATETIME, CURRENCY, etc. En la ayuda del Visual FoxPro los encontrarás a todos.

Artículos relacionados:

De DBF a SQL (1). Introducción

De DBF a SQL (2). Reemplazando comandos

De DBF a SQL (3). Entendiendo a los cursores

De DBF a SQL (4). Ejemplos de usar SELECT con una sola tabla

De DBF a SQL (5). Las funciones agrupadas

De DBF a SQL (6). Agrupando filas

De DBF a SQL (7). Poniéndoles condiciones a los grupos

De DBF a SQL (8). Ordenando las filas

De DBF a SQL (9). Uniendo tablas

De DBF a SQL (10). Obteniendo las primeras filas de una tabla

De DBF a SQL (11). Relacionando una tabla con otra tabla

De DBF a SQL (12). Relacionando una tabla consigo misma

De DBF a SQL (13). Relacionando a varias tablas entre sí

De DBF a SQL (14). Más sobre el uso de DISTINCT

De DBF a SQL (15). Usando subconsultas

De DBF a SQL (16). Más sobre las subconsultas

De DBF a SQL (17). Ejemplos de subconsultas

De DBF a SQL (18). Paginación

De DBF a SQL (19). Hallando los porcentajes sobre un total

De DBF a SQL (20). Los operadores especiales de comparación

De DBF a SQL (21). La técnica de los dos cursores

De DBF a SQL (22). Optimizando el uso del operador de comparación especial IN

De DBF a SQL (24). Buscando texto

De DBF a SQL (25).  Creando tablas y cursores

De DBF a SQL (26). INSERT, UPDATE, y DELETE, con subconsultas

De DBF a SQL (27). Entendiendo Cliente/Servidor

De DBF a SQL (28). Conectándose a un Servidor

De DBF a SQL (29). Las cadenas de conexión ODBC a los motores SQL más populares 

De DBF a SQL (30). Conectándose mediante ADO a las bases de datos

De DBF a SQL (31). Optimizando la escritura de los SELECT

De DBF a SQL (32). Mejorando la estética de los SELECT 

De DBF a SQL (33). Usando la función SQLEXEC()

De DBF a SQL (34). Enviándole parámetros a la función SQLEXEC()

El índice del blog VFPavanzado

 

De DBF a SQL (13). Relacionando a varias tablas entre sí

Ya hemos visto como relacionar a una tabla con otra tabla y también como relacionar a una tabla consigo misma. En este artículo veremos como relacionar a tres o más tablas.

Captura 1. Las filas de la tabla PRODUCTOS

 

Captura 2. Las filas de la tabla VENTASCAB

 

Captura 3. Las filas de la tabla VENTASDET

 

Ejemplo 1. Mostrando los productos vendidos en cada Factura

Captura 4. Viendo lo que se vendió en cada Factura

Al observar la Captura 4. seguramente has notado lo siguiente:

  1. Al nombre de cada columna se le puso un alias
  2. Se usó dos veces la cláusula JOIN
  3. Por cada venta realizada se puede ver la Fecha de esa venta, el Número de la Factura, que productos se vendieron, las cantidades vendidas, los precios unitarios de venta, y los totales vendidos de cada producto en cada venta

Ejemplo 2. Mostrando los nombres de los clientes

Vamos a hacerlo aún más interesante, mostraremos los nombres de los clientes a quienes se les vendió.

Captura 5. Las filas de la tabla CLIENTES

 

Captura 6. Las ventas realizadas

(Si ves el texto muy pequeño, puedes hacer clic en la imagen para verlo más grande)

Al observar la Captura 6. puedes notar que:

  1. A los clientes se los relacionó con la cláusula LEFT JOIN y no con la cláusula JOIN. ¿Por qué? para descubrir si hay identificadores de clientes que están en la tabla VENTASCAB (cabecera de ventas) pero no están en la tabla de CLIENTES. Y sí, existe ese problema. Son esos NULL que vemos.
  2. La tabla principal de nuestro SELECT es VENTASDET (porque se encuentra a continuación de la cláusula FROM), sin embargo la relación con los clientes se hizo a través de la tabla VENTASCAB. ¿Qué implica eso? Que se puede relacionar una tabla con cualquier otra tabla, no solamente con la tabla principal. Esa característica de SQL es extremadamente poderosa y deberías tomarla muy en cuenta porque te facilitará enormemente escribir SELECT complejos.
  3. El resultado obtenido del SELECT no está normalizado, pero eso no es un problema. Las tablas son las que sí deben estar normalizadas, no las consultas a esas tablas.

Conclusión:

Se puede relacionar a varias tablas entre sí, muy fácilmente, simplemente escribiendo el JOIN adecuado para cada caso (INNER, LEFT, RIGHT, FULL) y las columnas que establecen la relación.

La tabla principal es la que se encuentra a continuación de la cláusula FROM. Cuando se la relaciona con otra tabla, las columnas de esa segunda tabla pueden usarse como si pertenecieran a la tabla principal.

No es obligatorio que en una relación participe la tabla principal. Cualquier tabla puede relacionarse con cualquier otra tabla (si tienen columnas en común, desde luego). Y también una tabla puede relacionarse consigo misma. En todos los casos es como si las columnas de las tablas relacionadas pertenecieran a la tabla principal.

En general, es muy conveniente ponerles alias a las columnas para que a los usuarios les resulte más fácil entender las consultas.

Artículos relacionados:

De DBF a SQL (1). Introducción

De DBF a SQL (2). Reemplazando comandos

De DBF a SQL (3). Entendiendo a los cursores

De DBF a SQL (4). Ejemplos de usar SELECT con una sola tabla

De DBF a SQL (5). Las funciones agrupadas

De DBF a SQL (6). Agrupando filas

De DBF a SQL (7). Poniéndoles condiciones a los grupos

De DBF a SQL (8). Ordenando las filas

De DBF a SQL (9). Uniendo tablas

De DBF a SQL (10). Obteniendo las primeras filas de una tabla

De DBF a SQL (11). Relacionando una tabla con otra tabla

De DBF a SQL (12). Relacionando una tabla consigo misma

De DBF a SQL (14). Más sobre el uso de DISTINCT

De DBF a SQL (15). Usando subconsultas

De DBF a SQL (16). Más sobre las subconsultas

De DBF a SQL (17). Ejemplos de subconsultas

De DBF a SQL (18). Paginación

De DBF a SQL (19). Hallando los porcentajes sobre un total

De DBF a SQL (20). Los operadores especiales de comparación

De DBF a SQL (21). La técnica de los dos cursores

De DBF a SQL (22). Optimizando el uso del operador de comparación especial IN

De DBF a SQL (23). Usando la función CAST()

De DBF a SQL (24). Buscando texto

De DBF a SQL (25).  Creando tablas y cursores

De DBF a SQL (26). INSERT, UPDATE, y DELETE, con subconsultas

De DBF a SQL (27). Entendiendo Cliente/Servidor

De DBF a SQL (28). Conectándose a un Servidor

De DBF a SQL (29). Las cadenas de conexión ODBC a los motores SQL más populares 

De DBF a SQL (30). Conectándose mediante ADO a las bases de datos

De DBF a SQL (31). Optimizando la escritura de los SELECT

De DBF a SQL (32). Mejorando la estética de los SELECT 

De DBF a SQL (33). Usando la función SQLEXEC()

De DBF a SQL (34). Enviándole parámetros a la función SQLEXEC()

El índice del blog VFPavanzado