Grandes enigmas modernos

A raíz de este tuit de @PeliCornia:

¿Sois conscientes del gran enigma que debe significar para los niños cuando van al baño y les decimos “tira de la cadena”?

Se pueden llegar a plantear nuevos enigmas lingüísticos modernos como “colgar el teléfono”. Acciones que algunos hemos realizado de manera cotidiana pero que a día de hoy no tienen mucho sentido literal, y que el día de mañana lo seguirán utilizando sin tan siquiera saber muy bien porqué se dice así.

Pero esto no es nuevo, nosotros también utilizamos expresiones sin saber de dónde vienen o que su significado literal no tiene mucho sentido a día de hoy. Os dejo como tarea que me pongáis algunas que conozcáis. Venga, empiezo yo: “morder el polvo”.

Publicado en Bitácora, Internet

Hoy cumple 12 años la criatura

12-years

Doce años. Más de un tercio de mi vida. Y hablando de tercios, hoy habrá que tomarse alguno en honor al nacimiento de este humilde blog. Ya sé que muchos me dirán que casi no escribo, cierto, pero es que yo también he ido cumpliendo años. Además, la tecnología evoluciona, ahora perdemos más tiempo en redes sociales que antes ni existían. Pero sí, lo tengo abandonado al pobre.

Después de tantas transformaciones, tanto estéticas como de contenidos, me estoy planteando volver al formato “personal”. Total, aquí ya no entro ni yo, así que igual desparramo un poco lo que se me pase por la cabeza. Ya veremos, igual lo sigo dejando como bloc de notas, o igual no escribo más. Eso sí, el dominio lo tengo con renovación automática.

En fin, que son 12 años ya, 12 como 2 packs de 6 birras, ya sabes. Sean buenos, pero no demasiado.

Publicado en Internet, Microsoft

SQL Server: obtener fecha u hora de un datetime

Parece algo bastante obvio, pero más de una vez habrás tenido que obtener la fecha, sin la hora, de un campo datetime de SQL Server, probablemente para compararla con otra fecha, y has terminado por comparar día, mes y año por separado. Pues bien, hay una manera más fácil y limpia de conseguirlo.

Supongamos que queremos obtener solo la fecha de hoy:

CONVERT(DATE,GETDATE())

Si queremos la hora exacta de ahora mismo sin la fecha:

CONVERT(TIME,GETDATE())

Funciona exactamente igual con cualquier campo datetime y, por supuesto, devuelve un datetime.

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, Linux, Tecnología

Instalar TP-Link TL-WN725N v2 en Linux Mint

tp-link-tl-wn725n

El TP-Link TL-WN725N se hizo bastante famoso en el mundillo Linux, especialmente para los poseedores de una Raspberry Pi, por su reducidísimo tamaño, por una instalación sencilla y por la calidad fabulosa a coste ridículo. Sin embargo, eso era con la v1 que montaba el chip RTL8188CU, ya que con la v2 que monta el RTL8188EU la cosa se ha complicado un poco. Por suerte no es demasiado difícil instalar el controlador del nuevo chip, así que os lo explico en 10 sencillos pasos desde la consola. Y como casi todo tutorial apto para Linux Mint, funciona de igual manera para Ubuntu y cualquiera de sus derivados (como lo es el propio Mint).

  1. Instalar GIT (o actualizarlo si ya lo tienes instalado):
    :~$ sudo apt-get install build-essential git
  2. Descargar el driver desde GIT:
    :~$ git clone git://github.com/liwei/rpi-rtl8188eu.git
  3. Acceder a la carpeta donde se descargó el driver:
    :~$ cd rpi-rtl8188eu
  4. Compilar el driver:
    :~$ make
  5. Instalar el driver:
    :~$ sudo make install
  6. Escanear los módulos:
    :~$ sudo depmod -a
  7. Actualizar la memoria del kernel:
    :~$ sudo update-initramfs -u
  8. Cargar el nuevo módulo al kernel:
    :~$ sudo modprobe -v 8188eu
  9. Conectar el adaptador WiFi a un puerto USB.
  10. No hace falta reiniciar el equipo, el Network Manager ya debería reconocer el adaptador y mostrar las redes WiFi disponibles. Si no es así, con desactivar y volver a activar la red desde el propio Network Manager debería ser suficiente.

Como veis es muy sencillo y rápido, pero si os atascáis en algún punto u os surgen dudas ya sabéis que en los comentarios solucionaré lo que esté en mi mano.

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.