Publicado en Internet

ColdFusion: Listar columnas devueltas por CFQUERY en orden correcto

Normalmente sabemos qué columnas nos traemos de una query, y por eso las pintamos en el orden que nos interesa. Pero si quisiéramos mostrar los datos de una query sin necesidad de saber las columnas que traemos o, simplemente, son tantas que es muy laborioso escribir una línea para cada una, necesitas obtener el listado de columnas que nos devuelve la consulta.

ColdFusion nos ofrece ColumnList, pero si lo has probado sabrás que devuelve el listado de columnas pero en orden alfabético, no en el orden de la tabla o el especificado en la query.

<cfquery name="qry_alumnos" datasource="facultad">
  SELECT id_alumno, nombre, apellidos FROM Alumnos
</cfquery>
<cfoutput>#qry_alumnos.ColumnList#</cfoutput>

Nos devolvería:

apellidos,id_alumno,nombre

Sin embargo, hay una manera de conseguir mostrar los campos ordenados, y es utilizar la función getColumnList().

<cfset columnas = ArraytoList(qry_alumnos.getColumnList())>
<cfoutput>#columnas#</cfoutput>

Esto nos devolvería:

id_alumno,nombre,apellidos

Y así es como tendríamos un array de campos perfectamente ordenado tal y como debe ser, y no en orden alfabético.

Para completar os dejo el código para mostrar los resultados en una tabla HTML:

<table>
   <tr>
      <cfloop index="i" list="#columnas#">
         <td><cfoutput>#i#</cfoutput></td>
      </cfloop>
   </tr>
   <cfoutput query="qry_alumnos">
      <tr>
         <cfloop index="i" list="#columnas#">
            <td>#evaluate(i)#</td>
         </cfloop>
      </tr>
   </cfoutput>
</table>

En el primer bucle cfloop pinto los nombres de los campos y en el segundo los datos de cada registro.

Publicado en Internet

Comprobar si existe un archivo en el servidor con JavaScript

Como ya sabrás, JavaScript se ejecuta en el cliente, por lo que no puedes preguntar por cosas del servidor. Sin embargo, sería muy bueno tener una función que nos dijera si un archivo existe en el servidor para poder tomar decisiones al respecto.

Pues bien, la solución nos la da AJAX. Pedimos la cabecera del archivo que queremos comprobar y si nos devuelve un 404 es que no existe, así de fácil. Sé que al leer AJAX tendemos a tirar por jQuery, pero en este caso, al ser algo tan sencillo voy a explicarlo en JavaScript puro, que siempre es más rápido que tener que cargar un framework.

function existeUrl(url) {
   var http = new XMLHttpRequest();
   http.open('HEAD', url, false);
   http.send();
   return http.status!=404;
}

Como puedes ver, ni siquiera necesitas cargar el archivo ya que solicitamos sólo el ‘HEAD’ (no hacemos ni GET ni POST), por lo que aunque sea de 100 megas tendrás una respuesta rápida. La misma función se podría hacer preguntando si el status es 200, que sería que existe el fichero y la cabecera del mismo es correcta.

Por cierto, el false del open es para que la consulta sea síncrona y así el return se ejecute cuando haya terminado de solicitar la cabecera, no vaya a ser que la conexión sea muy pobre y no le de tiempo a hacer el send antes de tener la respuesta del open. La url es relativa al sitio web.

Publicado en Internet, Linux, Tecnología

BASH: enviar emails desde un servidor de correo externo con autenticación vía telnet

Prácticamente todos los servidores Linux incorporan un servidor de correo, así que es probable que nunca se te haya planteado este problema, pero hay veces que necesitas enviar un correo desde un servidor SMTP externo. Ésto es muy fácil de conseguir gracias a nuestro amigo telnet. Sin embargo, hoy queremos hacerlo de manera automática desde un script bash, es decir, sin tener que ir introduciendo los comandos telnet y además desde una cuenta de correo que requiere autenticación. Viene muy bien para programar tareas que envíen emails al finalizar, por ejemplo.

No me enrollo más, primero el código del script y luego una breve explicación:

#!/bin/bash
(
sleep 2
echo "HELO smtp.midominio.com"
sleep 2
echo "auth login"
sleep 2
echo "bWNsYXJlbnguY29tQGdtYWlsLmNvbQ=="
sleep 2
echo "TWNMYXJlblg="
sleep 2
echo "MAIL FROM:micorreo@midominio.com"
sleep 2
echo "RCPT TO:destino@sudominio.com"
sleep 2
echo "DATA"
sleep 1
echo "SUBJECT:texto_del_asunto"
sleep 1
echo "FROM:remitente"
sleep 1
echo ""
sleep 1
echo ""
sleep 1
echo "Cuerpo del mensaje"
sleep 1
echo ""
sleep 1
echo "."
sleep 2
echo "QUIT"
) | telnet servidor_smtp 25

Si estás familiarizado con telnet te será fácil entender el código, aunque quizá la tercera y la cuarta línea (sin contar los sleeps) te sorprendan, es la clave para hacer que todo esto funcione. Usuario y password deben ir codificados en base64. El resto es un telnet normal que ejecutarías por consola. Lo explico igualmente:

  1. HELO smtp.midominio.com: inicia la comunicación con el servidor que va a enviar el email
  2. auth login: le dice al servidor SMTP que la cuenta que vamos a usar para enviar el email requiere autenticación
  3. bWNsYXJlbnguY29tQGdtYWlsLmNvbQ==: usuario en base64
  4. TWNMYXJlblg=: contraseña en base64
  5. MAIL FROM:micorreo@midominio.com: dirección de correo que envía el email
  6. RCPT TO:destino@sudominio.com: destinatario del email
  7. DATA: le indicamos al servidor que estamos listos para enviarle todos los datos del email
  8. SUBJECT:texto_del_asunto: el asunto del email
  9. FROM:remitente: el remitente puede ser una dirección de correo o simplemente un nombre
  10. Dejando un espacio es suficiente, pero yo dejo dos para que no se haga líos
  11. Cuerpo del mensaje: el texto del email
  12. Antes del QUIT hay que poner un punto (.) para indicarle que ya hemos terminado de darle los datos
  13. QUIT: termina la comunicación
  14. telnet servidor_smtp 25: hace todo lo anterior tras conectarse por telnet al servidor_smtp por el puerto 25

No me voy a meter a profundizar en el telnet a un servidor SMTP porque obviamente hay muchísimas más opciones para decirle qué y cómo mandar el email, pero eso ya os lo dejo a vuestro gusto e investigación. Lo importante: poner entre paréntesis todas las instrucciones que queremos mandar por telnet y que el usuario y la contraseña para autenticarnos en el servidor estén en base64, puedes convertirlos desde esta web.

Ante cualquier problema, duda o errata los comentarios están activados.

Publicado en Internet

ASP: Mostrar ficheros que están fuera del sitio web

Veamos la situación en la que queremos mostrar un fichero, típicamente un PDF, un Excel o algún otro documento no HTML que queramos plasmar en la web, pero no queremos que el usuario conozca la URL del mismo para que sólo sea accesible desde la propia web, y no copiando la dirección en cualquier navegador. Una buena manera de conseguir ésto es sacando los ficheros fuera del sitio web, así ya no son accesibles vía URL. Pero el problema es: ¿y cómo muestro un fichero que está fuera del raíz de mi sitio web?

Pongámonos en situación. Si el sitio web está definido en el IIS en la ruta C:\webs\misitioweb, los ficheros que queremos ocultar vía URL los pondremos en C:\webs\docs. Obviamente, desde un ASP que esté dentro de misitioweb no vamos a poder acceder a docs, ya que está fuera del sitio web y el famoso Server.MapPath no admite “..” para subir de nivel fuera del mismo. Así que aquí viene la magia: el objeto “ADODB.Stream”. Sé que hay gente que podría pensar en utilizar el objeto FSO, pero éste sólo lee datos ASCII así que para PDFs o Excels no nos va a servir. Vamos al código:

rutadoc = "C:\webs\docs\documento.pdf"
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Open
objStream.Type = 1 ' Tipo binario, poniendo 0 sería tipo texto
objStream.LoadFromFile rutadoc
Response.ContentType = "application/pdf" ' El MimeType que corresponda
Response.BinaryWrite objStream.Read ' Aquí muestro el fichero
objStream.Close
Set objStream = Nothing

Creo que es bastante fácil de entender, simplemente creamos un objetivo de tipo Stream, lo abrimos, cargamos el objeto con el fichero en binario que queremos mostrar y lo mostramos. Funciona perfectamente bien y conseguimos el objetivo: mostrar un fichero en la web que está fuera en una ruta del sitio web, y por tanto, no es accesible mediante una URL escrita en el navegador directamente. Sólo una precaución, para que el Response.BinaryWrite funcione en Chrome y Firefox, es obligatorio poner el Response.ContentType correcto. Internet Explorer no lo necesita.

Espero que le sirva de ayuda a alguien y ante cualquier duda los comentarios están activados. Saludos.

Publicado en Internet, Linux, Tecnología

Redireccionar una web desde el Apache

Creo que a estas alturas ya todo el mundo sabrá que los buscadores, Google, penalizan bastante el contenido duplicado, es por eso que la misma web accedida desde dos URLs diferentes es una mala práctica a la hora de posicionarla. Es decir, mclarenx.com y www.mclarenx.com son webs distintas con el mismo contenido, y eso hay que evitarlo.

La mayoría de las webs utilizan la redirección 301 en el .htaccess para, por ejemplo, todo el tráfico que venga desde mclarenx.com lo redireccione a www.mclarenx.com. Y eso es suficiente, funciona y es lo que queremos que haga, porque así mclarenx.com nunca tendrá contenido.

Sin embargo, hoy voy a explicaros como hacer exactamente lo mismo, pero a nivel de Apache. La razón de hacerlo así es brindar a tus clientes un servidor web con redirección automática y sin duplicidad de contenidos, lo que mejorará su posicionamiento sin hacer nada, muy útil para quien tiene una web pero no conocimientos.

Abrimos el fichero para editarlo:

:~$ sudo nano /etc/apache2/sites-available/miweb

Normalmente tendrás algo parecido a esto:

ServerName www.mclarenx.com
# Además de todos los , DocumentRoot, Options, etc.

Todo eso debe quedar exactamente igual. Lo importante es crear un segundo en el que vamos a agregar la redirección:

ServerName mclarenx.com
RedirectMatch permanent ^/(.*) http://www.mclarenx.com/$1

Ambos bloques deben quedar independientes dentro del mismo fichero. Quien haya utilizado la redirección en el .htaccess le resultará muy familiar la nomenclatura, y es que finalmente hace lo mismo, pero sin tener que depender del desarrollador, ya que el subdominio www suele estar presente en prácticamente todas las webs, así que mejor incluirlo de serie en el Apache, y utilizar el .htaccess para las florituras.

Obviamente, tras modificar el fichero hay que ponerlo en producción:

:~$ cd /etc/apache2/sites-available/
:~$ sudo a2ensite miweb
:~$ sudo service apache2 reload
Publicado en Internet, Tecnología

Validar IBAN en JavaScript

IBAN

Si a estas alturas no has adaptado todavía tus aplicaciones web a la nueva normativa es porque te ha pillado el toro, sin discusión. Pero más allá de este pequeño detalle, si necesitas comprobar el IBAN con JavaScript y no logras dar con la tecla, no te preocupes, intentar dividir un número de 26 cifras en JavaScript es una tarea bastante compleja, como ya habrás descubierto si has caído aquí. Por suerte hay una forma diferente de calcular el módulo que con el operador ‘%’. Vamos allá.

// Función que devuelve los números correspondientes a cada letra
function getNumIBAN(letra){
   var letras = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
   return letras.search(letra) + 10;
}

// Función que calcula el módulo sin hacer ninguna división
function mod(dividendo, divisor){
   var cDividendo = '';
   var cResto = '';
   
   for (var i in dividendo){
      var cChar = dividendo[i];
      var cOperador = cResto + '' + cDividendo + '' + cChar;
     
      if (cOperador &lt; parseInt(divisor)){
         cDividendo += '' + cChar;
      }else{
         cResto = cOperador % divisor;
         if (cResto == 0){
            cResto = '';
         }
         cDividendo = '';
      }
   }
   cResto += '' + cDividendo;
   if (cResto == ''){
      cResto = 0;
   }
   return cResto;
}

// El típico trim que inexplicamente JavaScript no trae implementado
function trim(texto){
   return texto.replace(/^\s+/g,'').replace(/\s+$/g,'');
}

// Función que comprueba el IBAN
function validaIBAN(IBAN){
   IBAN = IBAN.toUpperCase();
   IBAN = trim(IBAN); // Quita espacios al principio y al final
   IBAN = IBAN.replace(/\s/g, ""); // Quita espacios del medio
   var num1,num2;
   var isbanaux;
   if (IBAN.length != 24){ // En España el IBAN son 24 caracteres
      return false;
   }else{
      num1 = getNumIBAN(IBAN.substring(0, 1));
      num2 = getNumIBAN(IBAN.substring(1, 2));
      isbanaux = IBAN.substr(4) + String(num1) + String(num2) + IBAN.substr(2,2);
      resto = mod(isbanaux,97);
      return (resto==1);
   }
}

Con esto deberías tener suficiente, siempre se pueden hacer más comprobaciones para afinar un poco, como validar que los dos primeros caracteres sean letras y el resto números, o adaptar comprobaciones de longitud y posición para cada país, pero eso ya se lo dejo a cada uno, que aquí lo complicado es lo del módulo.

Para terminar, voy a dejar la explicación de la normativa, supongo que ya la conoceréis de sobra pero nunca está demás leerlo sin parafernalia lingüística:

El IBAN está compuesto por 2 letras que son el código del país, 2 números que hacen de dígitos de control y hasta un máximo de 30 posiciones más para la cuenta, la cantidad exacta depende del país. En España son 20 dígitos para la cuenta, así que tendremos los IBAN de 24 caracteres en total.

La manera de comprobar que un IBAN es correcto es siguiendo los siguientes pasos (ejemplo: ES38 0081 0283 4100 0111 1416):

  • Transformar las letras en números según la siguiente serie: A = 10, B = 11, C = 12, etc. Por lo tanto para España sería E = 14 y S = 28
  • Pasar tanto los códigos de las letras del país como los dígitos de control al final de la numeración, quedando así: 0081 0283 4100 0111 1416 142838
  • Obtener el resto de dividir éste último número entre 97 (mod 97)
  • Si el resto es 1, el IBAN es correcto, en otro caso no lo es

Espero que os sirva y ante cualquier duda ya sabéis, comentarios aquí abajo.

Publicado en Internet, Microsoft, Tecnología

Instalar aspSmartUpload en Windows Server 2008

Se podría decir que aspSmartUpload es un componente obsoleto, deberías echarle un vistazo a XelUpload (sube ficheros con ASP sin instalar componente alguno), pero me consta que todavía hay gente que lo utiliza y me han pedido que explique como instalarlo ya que da bastantes problemas y la documentación es muy pobre, además contactar con los creadores es prácticamente imposible, así que allá va, es fácil, pero hay que seguir bien los pasos, si no, efectivamente, no funciona.

Doy por hecho que tienes las dos dll que dan vida al componente: aspSmartUpload.dll y aspSmartUploadUtil.dll.

Instalación

  1. aspSmartUpload.dll debe estar en una carpeta que no cuelgue de C:\Windows
  2. aspSmartUploadUtil.dll debe estar en la carpeta C:\Windows\SysWOW64
  3. Abre la línea de comandos en modo administrador
  4. Ve al directorio donde está aspSmartUpload.dll, por ejemplo: C:\Users\Administrador\aspsmartupload_3
  5. Ejecuta: regsvr32 aspSmartUpload.dll
  6. Te aparecerá una ventana por el trabajo bien hecho.

Errores conocidos

Si aparecen los mensajes “Module cannot be loaded” o “Specific module could not be found”, es que no has hecho caso a los dos primeros puntos de este tutorial.

Si aparece el mensaje “The Call to DllRegisterServer Failed with Error Code 0×80004005” es que no has abierto la línea de comandos en modo administrador.

Creo que no se me olvida nada. Si siguiendo estos pasos a rajatabla no te funciona, probablemente tengas un error en el código (pégalo en los comentarios y lo debatimos) o la versión del aspSmartUpload no es la 3 (que es la última y la que yo he probado).

Publicado en Tecnología

ReplaceAll en JavaScript

En todo lenguaje de programación es necesario un método para reemplazar caracteres por otros. En JavaScript tenemos replace() que funciona de la siguiente manera:

var textoOrigen = 'Hola mundo!';
var textoDestino = textoOrigen.replace('mundo','gente');
// RESULTADO: textoDestino = 'Hola gente!'

Hasta aquí todo bien, pero el método replace() sólo reemplaza la primera ocurrencia, es decir, si quisiéramos reemplazar todas las ‘o’ por ‘u’, en el ejemplo anterior, la cadena resultante sería ‘Hula mundo!’. Para solucionar este asunto y que se reemplancen todas las ‘o’ tendremos que utilizar una expresión regular:

var textoOrigen = 'Hola mundo!';
var textoDestino = textoOrigen.replace(new RegExp('o','g'),'u');
// RESULTADO: textoDestino = 'Hula mundu!'

La manera cómoda de utilizar esto sería:

var textoDestino = textoOrigen.replace(/o/g,'u');

Teniendo en cuenta que la ‘o’ va sin comillas. Esta segunda forma de expresarlo parece mejor, pero en ocasiones no lo es. Al prescindir de las comillas no podríamos poner una variable, lo cual sí podemos hacer con la primera solución.

Si no estás muy puesto en expresiones regulares, la ‘g’ te parecerá extraña, pero es la que indica que tiene que realizar la acción en todas las ocurrencias, que es precisamente lo que queremos. A continuación el resto de opciones:

g: realiza una búsqueda global (todas las ocurrencias)
m: realiza una búsqueda en múltiples líneas
i: realiza la búsqueda sin diferenciar mayúsculas y minúsculas

Se pueden utilizar a la vez, por ejmplo, RegExp(‘Mundo’,’gi’); Lo cual buscaría todas las ocurrencias de ‘Mundo’ sin importar las mayúsculas y minúsculas, es decir, valdría cualquiera de estas: ‘mundo’, ‘MUNDO’, ‘MunDo’, etc.

También os dejo una lista de caracteres especiales que pueden utilizarse como primer parámetro de RegExp:

. Cualquier caracter que no sea salto ni fin de línea
\w Caracter de texto
\W Caracter que no sea texto
\d Dígito
\D No dígito
\s Espacio
\S No espacio
\b Principio o fin de palabra
\B No es principio ni fin de palabra
\0 NULL
\n Intro
\f Avance de página
\r Retorno de carro
\t Tabulación
\v Tabulación vertical
\xxx Caracter especificado por el número octal xxx
\xdd Caracter especificado por el número hexadecimal xx
\uxxxx Caracter unicode especificado por el hexadecimal xxxx

Esto es todo amigos. El mundo de las expresiones regulares es enorme y fascinante, así que se puede conseguir casi cualquier cosa, pero para lo que nos concierne, con la ‘g’ tenemos suficiente. Si tenéis alguna duda estaré encantado de intentar solucionarla en los comentarios.

Publicado en Tecnología

Hacer split en J2ME

Una cadena de caracteres siempre se puede separar mediante un patrón y convertirlo en un array para su fácil manejo. Esto en Java, y muchos otros lenguajes de programación, lo hace el comando split. El problema es que en la versión J2ME (Java 2 Micro Edition, orientada a dispositivos móviles o de recursos restringidos) no existe tal, por lo que hay que combinar indexOf y subtring para conseguirlo. Vamos allá:

import java.util.Vector;

public Vector split(String cadena, String separador){
   Vector items = new Vector();
   int pos = 0;
   pos = cadena.indexOf(separador);
   while(pos >= 0){
      items.addElement(cadena.substring(0,pos).trim());
      cadena = cadena.substring(pos + separador.length());
      pos = cadena.indexOf(separador);
   }
   items.addElement(cadena);
   return items;
}

No creo que haga falta explicar nada del código, es muy sencillo y funciona a la perfección. La única salvedad es que he utilizado la clase Vector en vez de utilizar los arrays de toda la vida porque es más sencillo a la hora de agregar elementos sin preocuparte de los índices.

Espero que le sea útil a alguien.

Publicado en Bitácora, Tecnología

Nos vemos en el Android Developer Lab

Android Developer Lab

Para quien no lo sepa, este sábado se celebra en Fuenlabrada (Madrid) el Android Developer Lab. Una oportunidad única para que los desarrolladores nos acerquemos a Android de manera oficial, con gente tan importante como Reto Meier, uno de los Developer Advocate, que seguro nos mostrará cosas muy interesantes.

Obviamente este es un evento de plazas muy limitadas y se cerraron hace ya tiempo, pero si alguien ya sabe que va a ir que sepa que yo estaré por allí aprendiendo y aportando lo que sea necesario. En el email de confirmación nos han pedido que llevemos un portátil con el Android SDK 2.1 instalado así que seguro que será una reunción muy interesante.