Sobre la normativa de uso de cookies en sitios web

A raíz de la aparición de artículos de abogados haciendo referencia a las primeras sanciones por el uso “incorrecto de cookies”, concretamente este, he decidido publicar por aquí mi opinión sobre el tema.

Contexto

Hace relativamente poco tiempo, se aprobó una reforma por la cual se obligaba a los sitios web que instalasen cookies a notificar al usuario y pedir confirmación de que el mismo deseaba instalarlas en su navegador antes de que el sitio web lo hiciese.

La AEPD publicó una guía para explicar en detalle cómo y por qué se debe avisar al usuario de que el sitio web almacena información en su navegador.

Problema

Podemos decir que todos los sitios y aplicaciones web en Internet a los cuales se accede desde un navegador necesitan usar cookies. Hay excepciones, pero no pertenecen a lo que podemos calificar como sitio web o aplicación web normal.

Algunas cookies permiten que el usuario pueda iniciar sesión, otras recordarle aunque cierre el navegador para que no tenga que volver a indicar su usuario y contraseña, otras ayudan a mejorar la usabilidad y posicionamiento de la página, otras ayudan a mejorar la precisión a la hora de mostrar anuncios al usuario y otras tienen fines que podemos calificar de menos éticos.

Hasta ahora, el uso de las cookies se especificaba en los términos y condiciones del sitio web pero tras la reforma ya esto deja de ser suficiente y tendremos que avisar al usuario de que vamos a instalar cookies — antes de hacerlo — que hacen funcionar cosas tan normales como Google Analytics, videos de Youtube o el ya típico login  de Facebook.

El problema reside en que un aviso similar al que se pide puede echar atrás a una persona que no está entrenada o no entienda muy bien “los riesgos” que conlleva dejar al sitio web instalar las cookies.

Estamos viendo noticias de cómo Gobiernos espían a sus usuarios, cómo redes sociales hacen data mining con los datos de sus usuarios para venderlos a marcas o agencias de marketing, cómo se dan casos de estafa en sitios web y, aunque estas cosas tengan poco o nada que ver con el tema que estamos tratando, los usuarios ya tienen una desconfianza adquirida por ese contexto.

Esa desconfianza también es adquirida gracias a sitios web que permiten ver contenido online como series o películas, en las que al usuario se le bombardea con decenas de avisos en los que debe “aceptar o cancelar” y, dependiendo si se equivoca o no, puede acabar en un anuncio de contenido bien distinto a lo que buscaba.

Personalmente creo que el contexto no es favorable para añadir avisos o notificaciones que alerten al usuario de que vamos a hacer algo que llevamos haciendo desde que existe Internet y no tiene por qué suponer un riesgo a esa persona o su navegador.

Por otro lado, el rechazar el uso de cookies puede generar una mala experiencia de usuario que perjudique directamente al negocio y ventas.

Ni decir tiene que si un sitio instala cookies para mostrar publicidad al usuario y es su modelo de negocio principal, el que el usuario rechace las mismas puede suponer un problema muy serio para dicha empresa.

Una solución mejor

Aunque creo que es labor del usuario conocer de otra forma que existe un contrato con ese servicio y que en ese contrato se especifique cómo gestionar las cookies referentes a ese sitio web, pienso que una solución mejor sería que fuesen los navegadores los que se encargasen de la tarea de avisar al usuario por defecto, sin tener que configurar nada en los mismos.

De esta forma los usuarios aprenderían a reconocer y diferenciar este tipo de avisos, de otros como banners o advertencias que aparezcan en el propio sitio web.

Actualmente recae en el sitio web el poner la advertencia, y eso puede influir a que cada uno use un diseño y textos distintos, en idiomas distintos. Algo que algunos sitios web podrían usar en contra del usuario, mostrando avisos similares para confundirle y terminar llevándole a una página publicitaria o algo más ofensivo.

Cómo configurar el “remember me” en Silex

Hoy he implementado la funcionalidad de remember me en una aplicación Silex haciendo uso de los proveedores SecurityServiceProvider junto al RememberMeServiceProvider.

Al registrar el RememberMeServiceProvider me daba la siguiente excepción:

InvalidArgumentException: Identifier “security.remember_me.service.{key del firewall}” is not defined.

El problema residía en que registraba el RememberMeServiceProvider antes del SecurityServiceProvider, y eso era lo que lanzaba esa excepción.

Por lo tanto, para que funcione sin problemas deberíamos tener una configuración como la siguiente, respetando como he dicho el orden a la hora de registrar los proveedores de servicios:


$app->register(new Silex\Provider\SessionServiceProvider());


$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    'security.firewalls'    => array(
        'site'  => array(
               
               'remember_me'   => array(),
               'pattern'       => '^/',
               'anonymous'     => true,
               'form'          => array(
                          'login_path' => 'login',
                          'check_path' => 'login_check'
                ),
                'users' => $app->share(function () use ($app) {
                    return new \Lib\UserProvider($app);
                }),
                'logout' => array('logout_path' => 'logout'),
         ),
    ),
    'security.access_rules' => array(
         array('^/login', 'IS_AUTHENTICATED_ANONYMOUSLY')
    )
));

$app->register(new \Silex\Provider\RememberMeServiceProvider());

Symfony2 Security UsernamePasswordToken::serialize() must return a string or NULL

Today I got the following exception in a web application that uses Doctrine2 Entities and the Symfony Security Component with Silex framework (this can also appear in Symfony2 framework).

Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken::serialize() must return a string or NULL

ErrorException: Notice: serialize(): "id" returned as member variable from __sleep() but does not exist in /../vendor/symfony/security/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php line 149

The error appears when you have a Doctrine Entity implementing the UserInterface with a relation mapped in it.

The solution is as simple as implement the __sleep() magic method in that entity in this way.


public function __sleep(){
   return array('id', 'username', 'email');
}

This sets the id, email and username as the desired attributes to serialize ignoring the mappings and other properties in the Entity.

Conceptos sobre APIs REST

En esta entrada voy a resumir los conceptos más importantes que he tratado en mis ponencias sobre REST.

¿Qué es REST?

REST, REpresentational State Transfer, es un tipo de arquitectura de desarrollo web que se apoya totalmente en el estándar HTTP.

REST nos permite crear servicios y aplicaciones que pueden ser usadas por cualquier dispositivo o cliente que entienda HTTP, por lo que es increíblemente más simple y convencional que otras alternativas que se han usado en los últimos diez años como SOAP y XML-RPC.

REST se definió en el 2000 por Roy Fielding, coautor principal también de la especificación HTTP. Podríamos considerar REST como un framework para construir aplicaciones web respetando HTTP.

Por lo tanto REST es el tipo de arquitectura más natural y estándar para crear APIs para servicios orientados a Internet.

Existen tres niveles de calidad a la hora de aplicar REST en el desarrollo de una aplicación web y más concretamente una API que se recogen en un modelo llamado Richardson Maturity Model en honor al tipo que lo estableció, Leonard Richardson padre de la arquitectura orientada a recursos. Estos niveles son:

  1. Uso correcto de URIs
  2. Uso correcto de HTTP.
  3. Implementar Hypermedia.

Además de estas tres reglas, nunca se debe guardar estado en el servidor, toda la información que se requiere para mostrar la información que se solicita debe estar en la consulta por parte del cliente.

Al no guardar estado, REST nos da mucho juego, ya que podemos escalar mejor sin tener que preocuparnos de temas como el almacenamiento de variables de sesión e incluso, podemos jugar con distintas tecnologías para servir determinadas partes o recursos de una misma API.

Nivel 1: Uso correcto de URIs

Cuando desarrollamos una web o una aplicación web, las URLs nos permiten acceder a cada uno de las páginas, secciones o documentos del sitio web.

Cada página, información en una sección, archivo, cuando hablamos de REST, los nombramos como recursos.

El recurso por lo tanto es la información a la que queremos acceder o que queremos modificar o borrar, independientemente de su formato.

Las URL, Uniform Resource Locator , son un tipo de URI, Uniform Resource Identifier, que además de permitir identificar de forma única el recurso, nos permite localizarlo para poder acceder a él o compartir su ubicación.

Una URL se estructura de la siguiente forma:

{protocolo}://{dominio o hostname}[:puerto (opcional)]/{ruta del recurso}?{consulta de filtrado}

Por ejemplo, http://asiermarques.com/2013/conceptos-sobre-apis-rest/, sería la URL para visualizar este artículo.

Existen varias reglas básicas para ponerle nombre a la URI de un recurso:

  • Los nombres de URI no deben implicar una acción, por lo tanto debe evitarse usar verbos en ellos.
  • Deben ser únicas, no debemos tener más de una URI para identificar un mismo recurso.
  • Deben ser independiente de formato.
  • Deben mantener una jerarquía lógica.
  • Los filtrados de información de un recurso no se hacen en la URI.

Las URIs no deben implicar acciones y deben ser únicas

Por ejemplo, la URI /facturas/234/editar sería incorrecta ya que tenemos el verbo editar en la misma.

Para el recurso factura con el identificador 234, la siguiente URI sería la correcta, independientemente de que vayamos a editarla, borrarla, consultarla o leer sólo uno de de sus conceptos: /facturas/234

Las URIs deben ser independientes de formato

Por ejemplo, la URI /facturas/234.pdf no sería una URI correcta, ya que estamos indicando la extensión pdf en la misma.

Para el recurso factura con el identificador 234, la siguiente URI sería la correcta, independientemente de que vayamos a consultarla en formato pdf, epub, txt, xml o json: /facturas/234

Las URIs deben mantener una jerarquía lógica

Por ejemplo, la URI /facturas/234/cliente/007 no sería una URI correcta, ya que no sigue una jerarquía lógica.

Para el recurso factura con el identificador 234 del cliente 007, la siguiente URI sería la correcta: /clientes/007/facturas/234

Filtrados y otras operaciones.

Para filtrar, ordenar, paginar o buscar información en un recurso, debemos hacer una consulta sobre la URI, utilizando parámetros HTTP en lugar de incluirlos en la misma.

Por ejemplo, la URI /facturas/orden/desc/fecha-desde/2007/pagina/2 sería incorrecta ya que el recurso de listado de facturas sería el mismo pero utilizaríamos una URI distinta para filtrarlo, ordenarlo o paginarlo.

La URI correcta en este caso sería:

/facturas?fecha-desde=2007&orden=DESC&pagina=2

Nivel 2: HTTP

Conocer bien HTTP no es opcional para un desarrollador web al que le importe su trabajo. Aunque el RFC es sencillo de leer, si estás interesado en aprender bien las bases de este protocolo es muy recomendable la guía de O’Reilly sobre el mismo.

Para desarrollar APIs REST los aspectos claves que hay que dominar y tener claros son:

  • Métodos HTTP
  • Códigos de estado
  • Aceptación de tipos de contenido

Métodos.

Como hemos visto en el anterior nivel, a la hora de crear URIs no debemos poner verbos que impliquen acción, aunque queramos manipular el recurso.

Para manipular los recursos, HTTP nos dota de los siguientes métodos con los cuales debemos operar:

  • GET: Para consultar y leer recursos
  • POST: Para crear recursos
  • PUT: Para editar recursos
  • DELETE: Para eliminar recursos.
  • PATCH: Para editar partes concretas de un recurso.

Por ejemplo para un recurso de facturas.

GET /facturas Nos permite acceder al listado de facturas

POST /facturas Nos permite crear una factura nueva

GET /facturas/123 Nos permite acceder al detalle de una factura

PUT /facturas/123 Nos permite editar la factura, sustituyendo la totalidad de la información anterior por la nueva.

DELETE /facturas/123 Nos permite eliminar la factura

PATCH /facturas/123 Nos permite modificar cierta información de la factura, como el número o la fecha de la misma.

Quizá debido al desconocimiento o el soporte de ciertos navegadores, los desarrolladores web han usado, durante los últimos años, únicamente los métodos GET Y POST para realizar todas estas acciones. Si trabajamos con REST, esto sería un error de base y puede darnos problemas incluso a la hora de nombrar nuestros recursos, obligándonos a poner verbos en las URLs.

Códigos de estado.

Uno de los errores más frecuentes a la hora de construir una API suele ser el reinventar la rueda creando nuestras propias herramientas en lugar de utilizar las que ya han sido creadas, pensadas y testadas. La rueda más reinventada en el desarrollo de APIs son los códigos de error y códigos de estado.

Cuando realizamos una operación, es vitar saber si dicha operación se ha realizado con éxito o en caso contrario, por qué ha fallado.

Un error común sería por ejemplo:

Petición
========
PUT /facturas/123

Respuesta
=========
Status Code 200
Content:
{
  success: false,
  code:    734,
  error:   "datos insuficientes"
}

En este ejemplo se devuelve un código de estado 200, que significa que la petición se ha realizado correctamente, sin embargo, estamos devolviendo en el cuerpo de la respuesta un error y no el recurso solicitado en la URL.

Este es un error común que tiene varios inconvenientes:

  • No es REST ni es estándar.
  • El cliente que acceda a este API debe conocer el funcionamiento especial y cómo tratar los errores de la misma, por lo que requiere un esfuerzo adicional importante para trabajar con nosotros.
  • Tenemos que preocuparnos por mantener nuestros propios códigos o mensajes de error, con todo lo que eso supone.

HTTP tiene un abanico muy amplio que cubre todas las posibles indicaciones que vamos a tener que añadir en nuestras respuestas cuando las operaciones han ido bien o mal.

Es imperativo conocerlos y saber cuándo utilizarlos, independientemente de que desarrolles siguiendo REST.

El siguiente ejemplo sería correcto de la siguiente forma:

Petición
========
PUT /facturas/123

Respuesta
=========
Status Code 400
Content:
{
  message: "se debe especificar un id de cliente para la factura"
}

Tipos y formatos de contenido.

Cuando hablamos sobre URLs, vimos también que no era correcto indicar el tipo de formato de un recurso al cual queremos acceder o manipular.

HTTP nos permite especificar en qué formato queremos recibir el recurso, pudiendo indicar varios en orden de preferencia, para ello utilizamos el header Accept.

Nuestra API devolverá el recurso en el primer formato disponible y, de no poder mostrar el recurso en ninguno de los formatos indicados por el cliente mediante el header Accept, devolverá el código de estado HTTP 406.

En la respuesta, se devolverá el header Content-Type, para que el cliente sepa qué formato se devuelve, por ejemplo:

Petición
========
GET /facturas/123
Accept: application/epub+zip , application/pdf, application/json

Respuesta
=========
Status Code 200
Content-Type: application/pdf

En este caso, el cliente solicita la factura en epub comprimido con ZIP y de no tenerlo, en pdf o json por orden de preferencia. El servidor le devuelve finalmente la factura en pdf.

Nivel 3: Hypermedia.

A pesar de lo que nos pueda inducir a pensar el término retrofuturista Hypermedia, el concepto y la finalidad que busca describir es bastante sencillo: conectar mediante vínculos las aplicaciones clientes con las APIs, permitiendo a dichos clientes despreocuparse por conocer de antemano del cómo acceder a los recursos.

Con Hypermedia básicamente añadimos información extra al recurso sobre su conexión a otros recursos relacionados con él.

Aquí tenemos un ejemplo:

<pedido>
 <id>666</id>
 <estado>Procesado</estado>
 <links>
   <link rel="factura">
       http://example.com/api/pedido/666/factura
   </link>
 </links>
</pedido>

En este ejemplo vemos cómo indicar en un xml que representa un pedido, el enlace al recurso de la factura relacionada con el mismo.

Sin embargo, necesitamos que el cliente que accede a nuestra API entienda que esa información no es propia del recurso, sino que es información añadida que puede utilizar para enlazar el pedido con la factura.

Para ello conseguir esto, debemos utilizar las cabeceras Accept y Content-Type, para que tanto el cliente como la API, sepan que están hablando hypermedia.

Por ejemplo:

Petición
========
GET /pedido/666
Accept: application/nuestra_api+xml, text/xml

Respuesta
=========
Status Code: 200
Content-Type: application/nuestra_api+xml
Content:

<pedido>
 <id>666</id>
 <estado>Procesado</estado>
 <links>
   <link rel="factura">
        http://example.com/api/pedido/666/factura
   </link>
 </links>
</pedido>

Como vemos, el cliente solicita el formato application/nuestra_api+xml de forma preferente al formato text/xml. De esta forma, le indica al servicio web, que entiende su formato hypermedia y puede aprovecharlo.

El servicio web por lo tanto, como implementa hypermedia, le devuelve la información de recurso y la información de hypermedia que puede utilizar el cliente.

Hypermedia es útil por ejemplo para que el cliente no tenga que conocer las URLs de los recursos, evitando tener que hacer mantenimientos en cada uno de los mismos si en un futuro dichas URLs cambian (cosa que no debería pasar). También es útil para automatizar procesos entre APIs sin que haya interacción humana.

Conclusión

Como hemos visto, los principios básicos para construir APIs REST se basan en conocer sobre todo HTTP, algo que no es opcional para un desarrollador web.

Versiones en nuestra API REST

Una de las cosas que hay que tener en cuenta cuando hacemos una API es que esta, al igual que otro tipo de aplicaciones web, va a cambiar.

Si la API es pública o es consumida por una gran cantidad de clientes, es casi seguro que muchos de estos clientes queden obsoletos o no sigan al día las actualizaciones que tu equipo vaya haciendo en la misma.

La solución consiste en dar compatibilidad a las versiones anteriores y de alguna forma separar o que el cliente pueda indicar a qué versión está accediendo en cada momento.

Las opciones más habituales para hacer esto serían:

Indicar la versión de la API en la URL del recurso.

https://api.dominio.com/v1/recurso/

Este sería un ejemplo de URL en la que se indica la versión de la API en la misma.

Esta es la opción más aconsejada pero la que a mí personalmente menos me convence ya que los clientes que quisieran estar actualizados a la última versión, deberían modificar las rutas de sus llamadas al servicio constantemente.

Indicar como parámetro la versión de la API

https://api.dominio.com/recurso/?v=1

Este tipo de opción se usa por ejemplo en la API de YouTube.

Yo personalmente prefiero indicar como parámetros opciones para filtrar o tratar la información del recurso solicitado. Por ejemplo, paginaciones, órdenes, búsquedas, especificar información parcial etc.

Indicar como header la versión de la API

https://api.dominio.com/recurso/ 
“API version”: 1

Esta opción es la que más me convence, ya que no se ensucia la URL y si la aplicación cliente tiene las llamadas centralizadas en un único punto no debería ser problema añadir un header extra indicando la versión del API.

Después en el servidor podremos separar las versiones de las APIs en distintos servidores web o aplicaciones mediante un servidor proxy HTTP como Varnish que lea el header del request y sirva la versión de la API solicitada de forma transparente.

En javascript por ejemplo tendríamos el siguiente código para añadir un header http a nuestra llamada AJAX.


var request = new XMLHttpRequest();
request.open("GET", "https://api.dominio.com/recurso/", false);
request.setRequestHeader("API version", "1");
request.send();

En jQuery se añadiría el header de la siguiente forma.


$.ajax(
  "https://api.dominio.com/recurso/",
  {"headers": {"API version": "1"}}
);

En cualquier caso, se elija la opción que se elija es importante tener en cuenta que nuestra API puede cambiar en el futuro y facilitar la vida a los desarrolladores que programen los clientes de la misma siempre es una buena práctica.

Una reflexión sobre Symfony2 y sus componentes

Me ha alegrado leer la noticia que resume la reunión de ayer día 3 de Noviembre en symfony.es, proyecto que mantiene Javier Eguiluz, en la que dice que Fabien Potencier, autor y líder del proyecto Symfony, quiere dar prioridad a la documentación de los Componentes del framework.

Es una gran noticia que se considere documentar cada componente para final de año, y va muy en la línea de lo que comentaba Fabien en su blog sobre qué es Symfony2 y qué no.

Fabien quiere dar mucha importancia a los Componentes ya que es la única forma de que Symfony2 esté presente en el mayor número de proyectos posibles.

En mi opinión, y como ya he expresado en otras ocasiones, Symfony2 es un framework enorme, que intenta solucionar demasiada problemática, y en mi experiencia, cuanto más grande sea la aplicación y cuanta más problemática se intente cubrir, más complejo después será encontrar un posible fallo en entornos que no se hayan tenido en cuenta para la misma. En aplicaciones orientadas a internet, el entorno de sistemas puede que no sea el estándar LAMP, sobre todo si nos enfrentamos a webs de alto tráfico.

Otro problema, que para otros es una virtud, es que el framework intenta hacer configurable todo, con el objetivo de que los proyectos sean lo más automatizables, mantenibles y dotarles de una capacidad de reutilización en la que llegue a ser innecesario tocar una línea de código. Esto en teoría, suma más horas de desarrollo al principio y luego hace el mantenimiento más barato. Sin embargo, en proyectos que se orientan a internet, la teoría queda muchas veces en evidencia.

Hay que tener en cuenta que el mundo php5 no es como el mundo .net o java. Es complicado que desarrolladores web de php, aun con experiencia, se conviertan tan puristas de repente (más teniendo en cuenta los presupuestos tan ajustados económicamente y en tiempo que se barajan en proyectos web para internet) como para adoptar y entender todas las buenas prácticas que te obliga a usar Symfony2.

Para la mayoría de desarrolladores, el disponer de componentes, no les obliga a comprender el funcionamiento de todo el framework y pueden usarlos en desarrollos más simples o que ya tengan hechos.

De hecho, viendo estas direcciones en el proyecto Symfony2, en mi propio proyecto Leophard, un framework mvc ligero para php que por diversas razones de peso he tenido que retrasar su desarrollo, usaré algunos de estos componentes como el EventDispatcherUniversalClassLoader, el Routing, Pimple o el HttpFoundation, que son ligeros y resuelven problemática muy importante del proyecto.

La gente de Drupal está usando algunos de estos componentes también en la próxima versión de su cms.

Jugando con ips y redes en php

Por la naturaleza de mi entorno profesional, lidio con conceptos de IT y redes en mi día a día que me ayudan a tener frescos conceptos que aprendí hace ya algún tiempo cursando el temario del programa CCNA de Cisco y del MCSE de Microsoft.

Concretamente en el área de redes, es muy útil saber cómo hacer subredes o saber a qué red pertenece una ip en concreto haciendo operaciones AND binarias con las máscaras y direcciones a evaluar.

Refresco de conceptos

Las direcciones ip se clasifican en lo que llamamos “clases de red” según el número de hosts que dichas redes puedan soportar (siendo un host un ordenador, impresora o cualquier cacharro que conectemos a dicha red).

Usamos comúnmente las siguientes clases de red:

  • Clase C, la más común, que puede tener hasta 254 dispositivos host conectados.
  • Clase B, que puede tener hasta 65.534 dispositivos host conectados.
  • Clase A, que puede tener hasta 16.777.214 dispositivos host conectados.

Para saber de qué clase es una red o una dirección ip, usamos máscaras de red. Las máscaras de red se componen de 4 fracciones y en cada una podemos rellenar hasta 8bits.

En una dirección de clase C tendremos un total de 24bits, en binario podríamos expresarla entonces como 11111111.11111111.11111111.00000000 (24bits = 8bits + 8 bits +8bits + 0bits) y en decimal como 255.255.255.0 .

No necesitamos escribir la máscara completa para indicar que la ip 192.168.1.2 es de clase C por ejemplo, bastaría con indicar al final de la misma que su máscara tiene 24bits de la siguiente forma: 192.168.1.2/24 .

En el resto de clases, tendríamos 8bits para las redes de clase A y 16bits para las de clase B.

Sin embargo, aunque en entornos domésticos o de mediana empresa se usen estas clases de red para crear las redes a las cuales se conecten los ordenadores, servidores e impresoras de la organización, en una empresa que provee servicios de internet o que tiene muchos departamentos, le es muy útil poder partir esas redes en subredes.

Hay escenarios en los que nos interesa tener varias subredes con un número concreto de equipos en cada una de ellas. De esta forma aislamos a qué recursos puede acceder uno o varios equipos de una determinada subred.

Para hacer subredes lo que se suele hacer es usar máscaras de red personalizadas. Por ejemplo, si tenemos la ip 192.168.129.3/18, tal y como hemos visto antes sabemos que su máscara de red tiene 18bits, es decir en binario 11111111.11111111.11000000.00000000 y en decimal 255.255.192.0. Ahora bien, al no tener una máscara de 16bits o de 24, ya que tenemos una fracción de las 4 sin rellenar totalmente por bits en la máscara de subred, no podríamos decir que esa ip pertenece a la red 192.168.129.0/24, ya que esta sería una dirección de red de clase C y la nuestra no pertenece a esa clase.

Para saber a qué dirección de red pertenece tenemos que hacer una operación AND a nivel de bits binarios entre la dirección ip y su máscara de red.

En este caso la operación quedaría así:

Operación con ips

Al final deducimos que la dirección de red a la que pertenece la ip 192.168.129.3 es 192.128.0.0.

También podemos realizar operaciones para saber la cantidad de dispositivos que se pueden conectar a una determinada red o calcular una red que pueda albergar un determinado número de equipos.

Para calcular el número de dispositivos usamos la función 2x -2 donde X es la cantidad de bits disponibles en una subred es decir, el número de ceros que quedan al final de la misma. En la máscara de 18 bits que hemos usado en el ejemplo (11111111.11111111.11000000.00000000) serían 14 los bits disponibles (32bits posibles totales – 18 que estamos usando).

Aplicando la fórmula nos daría un total de 16.382 cacharros que podríamos conectar a nuestra red.

Utilizando php para realizar estos cálculos.

En php disponemos de una serie de funciones y operadores que nos hacen muy sencillo realizar cálculos de este tipo y automatizar este trabajo que de hacerlo manual nos haría consumir tiempo y estaría propenso a errores.

En este escenario utilizaremos tan sólo dos cosas:

  • La función ip2long para pasar una dirección ip separada por puntos a su representación numérica para poder realizar operaciones posteriores con ella.
  • La función decbin, para pasar de decimal a binario.
  • El operador bitwise & que es el que realizará la operación AND a nivel binario.

Volviendo al anterior ejemplo, podemos saber a qué dirección de red pertenece la ip 192.168.129.3/18 de la siguiente forma:


$ip_en_binario        = decbin( ip2long( "192.168.129.3" ) );

$mascara_en_binario   = decbin( ip2long( "255.255.192.0" ) );

$resultado_en_binario = $ip_en_binario & $mascara_en_binario;

echo long2ip( bindec( $resultado_en_binario ) );

Tal y como esperábamos, el resultado que nos devuelve este script es 192.168.128.0, que es la dirección de red a la que pertenece la ip 192.168.129.3/18.

Con este sencillo ejemplo vemos el juego que le podemos sacar a todo esto.

Por un lado se ve de forma clara que si queremos saber a qué red pertenece una ip dada de todas las que tenemos en nuestra empresa, las cuales almacenamos en una base de datos, bastaría con pasar a binario cada ip y compararla al resultado de la operación efectuada en el ejemplo.

Pero lo realmente útil es saber que podemos guardar en base de datos la dirección directamente en binario, ahorrando un espacio importante en la tabla al evitarnos usar un campo tipo texto (clave para el rendimiento con índices en motores como inndb de mysql) y realizar directamente la búsqueda contra el registro que necesitemos.

También podríamos conocer muy fácilmente con la formula que hemos visto antes, el número de equipos que puedo conectar a una red seleccionada y en base a las ips que podríamos tener registradas, los “huecos” e ips disponibles para los equipos nuevos que tenga que conectar a esa red en un futuro.

Idea: sistema de recomendación de contactos en Twitter

Desde hace un tiempo he estado dándole vueltas a un sistema de recomendación de contactos en twitter.

Filtrar por listas es efectivo para seguir las actualizaciones de las personas que más me interesa lo que suelen decir, pero de vez en cuando suelo consultar el stream del resto para captar nuevos contactos o enterarme de cosas que no veo en estas listas privadas.

He observado que podría automatizar el flujo de entrada y salida de contactos en las listas que he creado, para ello necesitaría crear un sistema que en base a ciertos patrones me sugiriese qué usuarios debo dejar de seguir en mis listas y cuales debo agregar.

Existen herramientas como http://www.muuter.com/ (gracias César por la recomendación), que permiten silenciar actualizaciones que contengan palabras que no quiero leer. Esto no me termina de convencer, ya que es posible que no me moleste que puntualmente un contacto diga “goool” (no me gusta el fútbol), o que mencione lo bueno que es su trabajo como SEO/socialmedia (bueno quizá en estos casos si que me vería tentado a dejar de seguirle :)

El sistema que propongo se basaría principalmente en lo contrario, es decir sería un sistema de recomendación basado principalmente en listas blancas.

De entrada se me ocurren los siguientes requisitos:

  • Dado que el sistema no me podría dar la información nada más registrarme, debería guardar mis contactos en su base de datos y evaluar sus updates cada cierto tiempo para compararlos a los criterios que he especificado en mis listas blancas y negras. Cada semana me podría sugerir nuevos cambios en mis listas privadas es decir, si debo agregar o quitar a alguien de las mismas.
  • Ya que la aplicación seguiría updates de mis contactos, y de los contactos de los demás usuarios, no estaría mal que me recomendase contactos que no esté siguiendo actualmente.
  • La aplicación analizaría mis propios updates, extrayendo las palabras que más repito usando estas como un criterio para distinguir una posible afinidad con respecto a otros usuarios. Podría tomar dichas palabras como criterios para una lista blanca y las que estén tageadas (es decir con #) en un update con la etiqueta #ironic en una lista negra.
  • La aplicación me permitiría poner una serie de filtros basados en expresiones regulares. Las expresiones regulares, aunque son difíciles para un usuario normal, permiten una mayor precisión de filtrado, que es lo que más me interesa. Gracias a ellas podría filtrar mucho más fácilmente usuarios que les guste el fútbol, hagan retweets sin aportar nada sobre temas que no quiero seguir o al revés, el sexo del contacto en base a las terminaciones sintácticas de ciertas palabras e infinidad de filtros mucho más flexibles que pudiese tener con simples palabras clave o la api del propio twitter. Estos filtros podría aplicarlos tanto en listas blancas como en listas negras.
  • Para dar más precisión a las listas blancas, la aplicación me permitiría especificar palabras clave y otros criterios más típicos en una aplicación de este tipo.

El algoritmo que evalúe qué contactos de twitter deben estar en las listas que sigo o cuales no, deberá calcular estas prioridades según los criterios descritos anteriormente y su recurrencia en los updates de estos usuarios. Es decir, si un usuario tiene muchos updates seguidos con criterios en una lista negra, se irá antes de mi bandeja de entrada que un usuario que tenga los mismos updates pero en intervalos de tiempo más largos y con otros updates de por medio que sí me interesen.

Pienso que podría ser una aplicación muy útil, si tenéis alguna sugerencia u os parece una tontería, dejad comentario.

Domo-kun and devil ducks

Siempre es interesante ver otros puntos de vista y aportaciones :)

Se necesita algo más que tecnología

“Software is a conversation, between the software developer and the user. But for that conversation to happen requires a lot of work beyond the software development.

It takes marketing, yes, but also sales, and public relations, and an office, and a network, and infrastructure, and air conditioning in the office, and customer service, and accounting, and a bunch of other support tasks.”

Joel Spolsky en su artículo The Development Abstraction Layer