Recomendaciones de anime – Temporada de otoño 2012

[anime]

Anime de la temporada de otoño 2012

Otra buena temporada de anime. La verdad es que nos están mal acostumbrando, aunque me da la impresión que se va a romper la tendencia con la inminente temporada de invierno… Mis recomendaciones esta vez son:

Jormungand PERFECT ORDER

Continúan las aventuras del niño soldado y la traficante de armas, y esta vez con una trama incluso mejor que la primera temporada, y manteniendo el buen elenco de personajes y sus escenas de acción. Ahora es el momento de ver las dos temporadas del tirón.

Medaka Box Abnormal

La primera temporada me pareció un tanto floja, aunque fue cogiendo fuerza según avanzaron los capítulos. Esta segunda temporada me ha gustado bastante más, lo suficiente como para recomendarla. Sigue siendo una serie bastante estúpida, pero es puro entretenimiento, y diría que por fin la Gainax de antaño se deja ver por momentos. Se deja todo preparado para una 3ª temporada, así que espero que siga está tónica ascendente.

Sword Art Online (SAO)

Uno de mis animes favoritos de los últimos tiempos. Sobretodo su primera mitad me pareció excelente, llena de capítulos memorables. La segunda mitad no está a la altura en cuanto argumento, pero mantiene el alto nivel de acción y animación. Sin duda la que más he disfrutado de esta temporada.

phpThumb no funciona con enlaces simbólicos

[linux] [programación]

Al menos eso era aparentemente mi problema, y mi punto de partida en búsqueda de una solución.

Básicamente el problema se podía resumir de la siguiente manera:

La imagen se ve correctamente:

http://www.midominio.com/imagenes/test.jpg

La imagen se ve correctamente y redimensionada:

http://www.midominio.com/phpThumb.php?url=imagenes/test.jpg&h=150

La imagen se ve correctamente. La carpeta “colecciones” es un enlace simbólico:

http://www.midominio.com/colecciones/imagenes/test.jpg

La imagen no se ve y phpThumb muestra un mensaje sobre el correcto uso del plugin:

http://www.midominio.com/phpThumb.php?url=colecciones/imagenes/test.jpg&h=150

Da la impresión que el problema aquí es ese enlace simbólico, pero no, este comportamiento se debe al siguiente valor de configuración de phpThumb:

$PHPTHUMB_CONFIG['allow_src_above_docroot'] = false;

En mi caso el enlace simbólico estaba apuntando a un directorio que estaba a un nivel superior que el contenido de la web, lo cual unido a este parámetro estaba bloqueando su acceso. La solución era tan simple como ponerlo a ’true'.

La solución la encontré en una de las últimas respuestas de este hilo.

Cositas útiles para Linux

[linux]

Almacenar en un fichero el listado de ficheros en un directorio:

find ./ -type f -print | tee ../listado.txt

Buscar que fichero contiene determinada frase de forma recursiva en un directorio:

grep -H -r "la frase" ./directorio

Cambiar los permisos de todos los ficheros de forma recursiva:

find ./ -type f -exec chmod 755 {} ;

Comprimir un directorio:

tar cvzf directorio.tar.gz ./directorio

Contar todos los fichero en un directorio y sus subdirectorios:

ls -R ./directorio | wc -l

Copiar una carpeta manteniendo la fecha de modificación de los ficheros:

cp -a -p ./directorio/ /destino/

Descomprimir un fichero:

tar xzvf directorio.tar.gz

Eliminar una carpeta y todas sus subcarpetas:

rm -rf DIRNAME

Mover todos los ficheros de un determinado tipo de la carpeta actual a otra carpeta:

find ./ -iname "*.extension" -type f -exec /bin/mv {} /carpeta/destino ;

Mover todos los ficheros y directorios de una carpeta al nivel superior:

mv ./directorio/* .

Mover todos los ficheros y directorios a una subcarpeta:

mv !(subcarpeta) subcarpeta

Listar todos los discos disponibles:

lsblk o fdisk -l

Listar todos los ficheros zip ordenados por fecha:

ls -alt *.zip

Recomendaciones de anime – Temporada de verano 2012

[anime]

Anime de la temporada de verano 2012

Esta temporada de verano ha sido realmente entretenida, con un buen número de series de las que he disfrutado. Sin embargo, series excepcionales han habido pocas.

Binbou-gami ga!

La mejor comedia de la temporada. Me he reído un montón con esta serie, y eso es más que suficiente para recomendarla. Tiene algunos cliclés, y tal vez le sobre algún chiste de tetas, pero por lo demás, diversión garantizada.

Natsuyuki Rendezvous

Esta es una interesante mezcla de drama y comedia, con un ligero componente paranormal. La recomiendo principalmente porque la primera mitad de la serie es genial. El problema es la falta de ritmo de su segunda mitad, llegando al punto que parece que la trama apenas avanza en los último capítulos, y por último la conclusión es muy precipitada. Pero pese a sus defectos, sigo pensando que ha sido una buena serie.

Tutorial de Flexi auth #1 – Primeros pasos

[programación]

Gracias a un amigo, he descubierto CodeIgniter. Es un framework de PHP para desarrollar aplicaciones rápidamente y la verdad es que es una pasada. Según va cogiendo fuerza, van saliendo extensiones para CodeIgniter, y una de ellas es Flexi auth, el cual añade toda la funcionalidad para autenticación y permisos de usuario. El problema es que a diferencia de CodeIgniter, que tiene muy buena documentación paso a paso de como hacer las cosas, la documentación de Flexi auth es muy pobre. Tiene un buen tutorial de instalación y después te dicen “Mira, ahí tienes un ejemplo de las principales funcionalidades. Mírate el código”. La demo está muy completa, y ese es su fallo, tiene demasiada información para alguien que lo único que quiere es empezar poco a poco.

Así pues, voy a poner aquí lo imprescindible para tener la funcionalidad más básica del Flexi auth, que es hacer Login y Logout.

En mi sencillo ejemplo uso un único controlador, que es pages.php, siguiendo el ejemplo del tutorial de CodeIgniter. Solo voy a ir poniendo código que no apareciera en dicho tutorial.

El constructor de la clase Pages sería el siguiente:

public function __construct() {
    parent::__construct();
    $this->auth = new stdClass;
    $this->load->library('flexi_auth');
    $this->load->helper('url');
}

La creación del objeto auth es imprescindible para el funcionamiento de la librería Flexi auth, y después cargamos la librería extendida que nos dará la funcionalidad para el Login/Logout. El ayudante para URLs es útil a la hora de componer direcciones en las vistas, así como para las redirecciones.

public function login() {
    $this->load->helper('form');

    $this->load->library('form_validation');

    // Set validation rules.
    $this->form_validation->set_rules('login_identity', 'Usuario', 'required');
    $this->form_validation->set_rules('login_password', 'Contraseña', 'required');

    // Run the validation.
    if ($this->form_validation->run()) {
        // Verify login data.
        $this->flexi_auth->login($this->input->post('login_identity'), $this->input->post('login_password'));

        // Save any public status or error messages
        // (Whilst suppressing any admin messages) to CI's flash session data.
        $this->session->set_flashdata('message', $this->flexi_auth->get_messages());

        // Reload page, if login was successful, sessions will
        // have been created that will then further redirect verified users.
        redirect('home');
    } else {
        // Set validation errors.
        $this->data['message'] = validation_errors('<p class="error_msg">', '</p>');

        return FALSE;
    }
}

Esto está íntegramente sacado del código de la demo del Flexi auth, pero eliminando todo lo que no vamos a necesitar. Al final, solo dejamos primero la validación del formulario de Login, y si todo está correcto, intentamos hacer Login. Si hay éxito hacemos una redirección a la página principal, y en caso contrario, podemos mostrar un mensaje al usuario.

public function logout() {
    // By setting the logout functions argument as 'TRUE', all browser sessions are logged out.
    $this->flexi_auth->logout(TRUE);

    // Set a message to the CI flashdata so that it is available after the page redirect.
    $this->session->set_flashdata('message', $this->flexi_auth->get_messages());

    redirect('home');
}

Más sencillo imposible. Creo que el código es bastante autoexplicativo. Vamos a por el formulario de Login. Este está en una vista llamada login.php:

<h2>Login</h2>
<?php echo validation_errors(); ?>
<?php echo form_open('login/login');?>

    <label for="identity">Usuario</label>
    <input type="input" id="identity" name="login_identity" /><br />
    <label for="password">Contrase&ntilde;a</label>
    <input type="password" id="password" name="login_password" /><br />
    <input type="submit" name="login_user" id="submit" value="Login" />

</form>

Dos campos de texto (nombre de usuario y contraseña) y un botón. Importante que los nombres sean los mismos que tenemos en el método de Login.

También he introducido un poco de código en la cabecera de las páginas para que se muestre la información del estado del usuario (si está logueado o no):

<p>
    <?php
    if ($this->flexi_auth->is_logged_in()) {
    ?>
        Usuario: <?php echo $this->flexi_auth->get_user_identity(); ?>
        &nbsp;|&nbsp;<a href="<?php echo base_url('logout'); ?>">Salir</a>
    <?php
    } else {
        echo 'Usuario no registrado';
    }
    ?>
</p>

Simplemente compruebo si el usuario está logueado, en cuyo caso muestro su identificación y un enlace de Logout.

Por último falta añadir un par de rutas a routes.php:

$route['login/login'] = 'pages/login';
$route['logout'] = 'pages/logout';

Y con eso ya debería funcionar. En el próximo post haré el proceso de registro.

Si no estás con un operador movil virtual, no se a qué esperas!

[mundo real] [reflexiones]

Evidentemente habrá quien tenga que estar casi obligado a estar con alguno de los operadores tradicionales, y habrá gente que consumirán tanto teléfono que les compense estar con algún paquete que le permita hablar muchos minutos al mes. Pero a la gente como yo que hace casi toda su comunicación por internet, y solo usa el móvil para casos puntuales, las operadoras virtuales (OMV) son la solución. Conozco a bastante gente que está con Simyo, y la verdad es que las tarifas de Internet 3G tienen buena pinta. Yo por mi parte estoy con Pepephone, y no podría estar más contento. Pago alrededor de 1€ al mes, y la atención al cliente es excelente, tanto por mail como por teléfono.

Hoy he recibido una llamada de ONO ofreciéndome tarifa de movil, y entre que me han despertado de la siesta, y la actitud del comercial, me han puesto un poco de mala hostia… La conversación ha sido algo así:

[Comercial de ONO] Buenas tardes! A través de nuestra campaña de fidelización queremos ofrecerle incluir la tarifa de móvil a su contrato actual.

[Yo] (Aún un poco sopa, y necesitando aclaración) ¿Me estáis ofreciendo tener el móvil con ONO?

[ONO] Sí señor. Y con nuestras tarifas de …

[Yo] (Le corto porque veo por donde va) Actualmente pago 1€ de móvil al mes. ¿Voy a pagar menos con vosotros?

[ONO] (Ni caso) Nuestras tarifas incluyen llamadas …

[Yo] (Le vuelvo a cortar) A ver, que no me estás entendiendo. Yo estoy pagando 1€ al mes. ¿Me vas a hacer una oferta mejor que esa?

[ONO] (Mira su guión y sigue leyendo) El contrato mínimo es de 6€ al mes, y tendría derecho a …

[Yo] (Este también está espeso) Luego no voy a pagar menos de 1€ al mes.

[ONO] (Parece que empieza a escuchar) Señor, tiene usted contrato o prepago.

[Yo] Contrato.

[ONO] Usted no puede estar pagando menos de 1€ al mes con contrato.

[Yo] (Juas! Se ha quedado a gusto. Ahora sabrá él lo que gasto yo de teléfono al mes) Pues sí. Pago alrededor de 1€ al mes.

[ONO] (Me toma por loco o se da por vencido, no estoy seguro) Buenas tardes señor.

[Yo] (La educación que no falte) Buenas tardes!

Está claro que este comercial no tiene ni idea de lo que es una OMV, y supongo que ni falta le hace. Lo que me sorprende es la cantidad de gente de este país que tampoco tiene ni idea y sigue pagando religiosamente a los operadores tradiciones sin haber buscado siquiera una alternativa.

SPAM Fight – Round 4!

[blog] [programación]

Cuando pensaba que había encontrado el método definitivo anti-spam, resultó no ser eficaz ni durante un día entero. Algunos de los comentarios se estaban marcando correctamente como SPAM, que deben ser los que atacan directamente a wp-comments-post.php. Sin embargo seguían llegando algunos comentarios de SPAM, y no tengo ni idea de como lo están haciendo. Debe haber otra manera de hacer un POST de un comentario, pero por el momento no la he encontrado.

Lo que sí que me he dado cuenta, es que estos comentarios nunca tienen establecido un correo electrónico (al menos de momento). Utilizando ese dato, he complementado el método de identificación de SPAM con el requerimiento de un correo. En wp-includes/comment.php:

if(strpos($comment_content, '[THIS#IS#SPAAAM!]') !== false
    || !is_email($comment_author_email)){
    $comment_approved = 'spam';
}

De momento con esto estoy cazando todo el SPAM. ¡Veremos si dura!

Adaptar manga para el Sony Reader PRS-T1

[gadgets] [software]

Hace ya un tiempo que llevaba queriendo comprarme un lector de libros electrónicos. Entre unas cosas y otras lo he ido postergando y por fin me decidí hace unas semanas. La duda estaba entre el Kindle y el Sony Reader PRS-T1. Si hubiese sido solo para leer libros, me habría comprado el Kindle, pero teniendo en cuenta que también lo quería para leer manga, el Kindle tiene un fallo vital, y es que sus 2 GB de almacenamiento dan para pocos mangas, mientras que el T1 tiene una ranura para micro-SD y con los 32 GB que le he metido ya se puede funcionar en condiciones.

Así que estas semanas he estado haciendo pruebas para ver cual es la mejor manera de meter los mangas. Estos son los pasos que estoy siguiendo ahora:

  1. Eliminar páginas innecesarias.
    En esta categoría entran muchas cosas, como por ejemplo las páginas de créditos de los equipos de traducción, páginas en blanco, páginas extra que no están traducidas, páginas a color que también tienen versión en blanco y negro, etc.
    Para ayudarme uso el programa VisiPics. De los programas de búsqueda de imágenes duplicadas, es el que mejores resultados me ha dado. Poniendo el filtro en “Loose” encuentra la gran mayoría de las páginas a eliminar.

  2. Dividimos el manga en grupos de tomos.
    Esto dependerá del manga. Por ejemplo, un manga que esté acabado y sean 7 tomos, los podemos meter todos en un único paquete. Pero para mangas más largos, o que aun se están publicando, yo he decidido dividirlos en 5 tomos por paquete. Esto lo hace mucho más manejable para los siguientes pasos, así como hacer que el lector lo abra más rápido. También es más fácil de actualizar si cada 5 nuevos volumenes creamos un nuevo paquete, que intentar actualizar un paquete que contenga todos los tomos. Por tanto, metemos el contenido de 5 tomos en una carpeta. Es importante que las imágenes queden ordenadas por nombre, para que después se puedan leer en orden correcto. Con la “Vista en miniatura” del explorador podemos dar un último vistazo por si se ha escapado alguna imagen que no queramos en el paquete.

  3. Cortamos las imágenes de doble página en dos páginas individuales.
    Hacemos esto porque más adelante estas imágenes pasarán a estar apaisadas. El problema es que si hay algo de texto en la imagen, pasará a ser diminuto y en ocasiones será ilegible. Para ello he hecho un pequeño programita en JAVA que buscará todas las imágenes de doble página y creará dos imágenes adicionales, con las dos mitades. Así podemos disfrutar de la vista panorámica, así como poder leer el texto en las nuevas imágenes creadas. Podéis descargar el programa de aquí.

  4. Usamos el mangle4reader para crear el paquete CBZ.
    Mangle es un programita increíble. Su uso original es el de convertir Manga para Kindle (de ahí su nombre), reduciendo el tamaño de las imágenes y convirtiendo la paleta de colores a la del Kindle. La alternativa sería hacer este paso con el Calibre, pero Mangle consigue una mejor calidad de imagen y con la mitad del tamaño que da Calibre. El inconveniente del Mangle es que saca las imágenes a una resolución de 600×800, pero para el Reader necesito una resolución de 584×754. Si no le damos este tamaño, Calibre después hará su propia conversión, con la consecuente pérdida de calidad y el doble del tamaño. Por ello he realizado unas modificaciones al Mangle, rebautizandolo como mangle4reader, para que nos de la resolución necesaria para el Reader. Te puedes bajar el código aquí. Por el momento no he conseguido hacer un ejecutable, por lo que hay que tener Python instalado para que funcione. Tenéis las instrucciones en la web del Mangle. En cuanto a las opciones del mangle4reader, yo las dejo como vienen por defecto.

  5. Añadir el libro a Calibre y convertirlo a epub.
    Una vez lo tenemos añadido, editamos sus metadatos. Al ser un grupo de volúmenes dentro de un manga mayor, el nombre que le suelo dar es “El manga que sea – Volúmenes del 01 al 05”. Añadimos también el autor, y por último en “serie” ponemos “El manga que sea” e indicamos que número es. Del 1-5 será el 1, del 6-10 será el 2, etc. Esto es muy útil porque después en el Reader podemos navegar por colecciones y accedemos muy rápidamente a un grupo de volumenes en concreto. También debemos indicar cual queremos que sea la portada. Yo suelo usar la del primer tomo dentro del grupo (1, 6, 11, …).

A la hora de convertir, estas son las opciones que debemos marcar:

Table of contents

  • Do not add detected chapters to the Table of Contents

Comic Input

  • Disable  comic processing (Ya se ha encargado el Mangle de esto)
  • Don’t add links to pages to the Table of Contents for CBC files

Epub output

  • Preserve cover aspect ratio

Le damos a OK y a esperar. Suele tardar unos 5-7 minutos. Por último enviamos el epub al Reader, ¡y a disfrutar del manga en cualquier parte!

El retorno del SPAM

[blog] [programación]

La solución con la base de datos de SPAM debo reconocer que fue ingeniosa. Está muy en mi línea de “matar moscas a cañonazos”. El problema es que lo que se dice eficaz, no era. Digamos que el número de direcciones IP desde las que puede llegar SPAM, o el número de direcciones de correo o URLs que pueden usar en los comentarios están en un orden de magnitud tal que nunca voy a ser capaz de filtrar los comentarios basura.

Todo vuelve a la pregunta que me hice hace ya hace 9 meses: ¿Como estaban los bots de SPAM enviando comentarios saltándose el formulario de envío? Y por pura casualidad, encontré a que página están atacando. Probablemente están haciendo un POST directamente contra wp-comments-post.php.

Así que volvemos a la sencillez. ¿Como detectar un POST que llega a wp-comments-post.php sin pasar por comments.php? Fácil. Si los bots están lanzando un POST genérico para blogs en WordPress, añadamos un nuevo campo al formulario. Si en wp-comments-post.php detectamos que ese campo no está establecido, entonces se está saltando comments.php y debe ser SPAM. Está solución es tan eficaz que hace que mis dos soluciones anteriores queden obsoletas, así que para aligerar la página y reducir tiempo de procesado, elimino las modificaciones del código anteriores. El código definitivo quedaría de la siguiente manera:

Dentro de los ficheros del tema, en el fichero comments.php:

Añadimos un nuevo campo oculto al formulario:

<input type="hidden" id="comment_post_antirobot" name="comment_post_antirobot" value="0" />

Por si acaso el robot de SPAM está comprobando que campos tiene el formulario, cambiamos su valor por javascript:

<script type="text/javascript">
  document.getElementById('comment_post_antirobot').value = "1";
</script>

En wp-comments-post.php:

Obtenemos el valor del campo oculto, y en caso de no estar establecido o no ser igual a 1, marcamos el comentario como SPAM modificando el contenido:

$comment_antirobot    = ( isset($_POST['comment_post_antirobot']) ) ? trim($_POST['comment_post_antirobot']) : null;

if( empty($comment_antirobot) || $comment_antirobot == '0'){
    // It's SPAM
    $comment_content = '[THIS#IS#SPAAAM!] '.$comment_content;    
}

En wp-includes/comment.php, en el método wp_insert_comment:

Comprobamos si contiene la marca de SPAM en su contenido, y en ese caso lo etiquetamos como SPAM:

if(strpos($comment_content, '[THIS#IS#SPAAAM!]') !== false){
    $comment_approved = 'spam';
}

De momento, el SPAM que está llegando se está etiquetando todo automáticamente como tal. A ver cuanto dura la solución… aunque en esta tengo bastante confianza!

El SPAM contraataca!

[blog] [programación]

El método que implementé contra el SPAM, que comenté en esté articulo, ha estado funcionando bien, pero en los últimos 2 meses ha dejado de cazar todo el SPAM. Los últimos comentarios que están llegando sí que  traen el campo de email cumplimentado, por lo que ya no es efectivo. Dándole vueltas al asunto, se me ha ocurrido hacer mi propia base de datos anti-spam. La idea es que cada vez que llega un nuevo comentario, se comprueba con la base de datos si es SPAM, y en caso que lo sea, añadir sus datos para futuras comprobaciones. El código es el siguiente:

En wp_includes/comment.php en el método wp_insert_comment, justo antes de insertar el comentario hago esta comprobación:

if(!is_email($comment_author_email)){
    $comment_approved = 'spam';
}
else{
    $spam_query = "SELECT * FROM spam_data "
    ."WHERE data = '".$comment_author_IP
    ."' OR data = '".$comment_author_email
    ."' OR data = '".$comment_author_url."'";

    /*$spam_query = "SELECT * FROM spam_data "
    ."WHERE 1";*/

    $spam_results = $wpdb->get_results($spam_query);

    /*if(count($spam_results) <= 0){ // It's SPAM
        $comment_approved = 'spam';
    }*/

    if(count($spam_results) > 0){ // It's SPAM
        $comment_content .= " count: ".count($spam_results);
        $comment_approved = 'spam';

        insert_into_spam_data($comment_author_IP);
        insert_into_spam_data($comment_author_email);
        insert_into_spam_data($comment_author_url);
    }    
}

Y para añadir los datos a la BD he añadido este método:

function insert_into_spam_data($spam_data){
    global $wpdb;

    $spam_query = "SELECT * FROM spam_data "
    ."WHERE data = '".$spam_data."'";

    $spam_results = $wpdb->get_results($spam_query);

    if(count($spam_results) <= 0){
        $wpdb->insert(
            'spam_data',
            array(
                'data' => $spam_data
            ),
            array(
                '%s'
            )
        );
    }
}

Esto debería parar una buena parte del SPAM. El siguiente paso será que cuando yo marque manualmente un comentario como SPAM, sus datos también sean incluidos en la tabla con la información de SPAM. Para ello en el metodo wp_spam_comment, tras marcar el comentario como SPAM, añadimos este código:

insert_into_spam_data($comment->comment_author_IP);
insert_into_spam_data($comment->comment_author_email);
insert_into_spam_data($comment->comment_author_url);

Ahora faltará ver como de efectivas son las medidas. Me estoy planteando introducir algún otro tipo de comprobación anti-spam, viendo que el captcha no está funcionando. Pero eso para otro artículo más adelante 🙂