Weblogs Código

Variable not found

Lanzados .NET Core, ASP.NET Core y Entity framework Core 1.0 RTM

June 28, 2016 09:04 AM

ASP.NET Core¡Por fin! Tras un desarrollo muy largo y convulso, ayer se presentaron las respectivas versiones 1.0 RTM de .NET Core, ASP.NET Core y Entity Framework Core, junto con actualizaciones de una serie de productos relacionados.

La verdad es que hace tan sólo unos años, presentar la nueva versión de ASP.NET en la conferencia Red Hat DevNation habría resultado una auténtica osadía y probablemente habría acabado con tomates volando hacia el escenario. Pero esto es agua pasada, y este simple gesto es una prueba más de que realmente las cosas han cambiado en Microsoft.

Con el lanzamiento de la versión 1.0 de la infraestructura .NET Core y el conjunto de frameworks basados en ella (ASP.NET, MVC, Entity Framework), iniciamos una nueva época en la que aquél sueño de desarrollar o ejecutar fácilmente aplicaciones .NET en cualquier plataforma es ya una realidad, y con todo el soporte y las bendiciones del gigante de Redmond. Escenarios antes impensables, como desarrollar desde Mac para desplegar en Linux, o crear nuestras aplicaciones en Windows y explotarlas desde un contenedor Docker, son ya posibles.

Estamos ante un reboot en toda regla: todos estos frameworks han sido construidos desde cero teniendo en mente conceptos actuales que ni siquiera existían cuando empezaron a gestarse las versiones iniciales de .NET o ASP.NET "clásicos": la nube, alto rendimiento, escalabilidad, APIs, múltiples dispositivos y plataformas, contenedores, microservicios etc. Y creados usando principios y buenas prácticas que tampoco eran los habituales antaño: inyección de dependencias, clases con responsabilidades limitadas, modularidad, componibilidad, abstracciones basadas en interfaces, pruebas unitarias…

Resumiendo, ayer se lanzaron, entre otras cosas:
Con estas novedades ya tenemos entretenimiento para una temporada, ¿que no? ;)

Y la pregunta del millón: ¿debo migrar ya a ASP.NET Core?

Oficialmente, ASP.NET Core se encuentra ya en RTM, lo que quiere decir que está listo para ser utilizado para desarrollar y explotar aplicaciones reales. Las recomendaciones son:
  • No intentar portar a ASP.NET Core aplicaciones existentes, pues el esfuerzo necesario para ello es comparable a lo que supuso el salto de Web Forms a MVC. Si fuera necesario hacerlo, se recomienda afrontarlo más como una reescritura que como una migración.
     
  • Sí serían candidatas a darle la oportunidad a ASP.NET Core aquellas aplicaciones que vayan a desarrollarse desde cero, o bien cuando sean necesarias características exclusivas de este nuevo framework como el soporte multiplataforma (por ejemplo, si necesitamos desplegar sobre Docker).
Y ahora hago yo mi aportación personal al respecto ;) Abstrayéndonos un poco del entusiasmo que despiertan estas novedades y de las ganas que sin duda todos tenemos de hincarle el diente en proyectos reales, hemos de ser conscientes de que estamos ante productos que acaban de salir del horno, aún incompletos en algunos aspectos, y que seguirán evolucionando durante los próximos meses. Aún su ecosistema y comunidad son relativamente pequeños, y al romper con las versiones anteriores hay puntos en los que partiremos desde cero.

Mi recomendación, por tanto, sería actuar con prudencia y estudiar detenidamente las necesidades que tenemos antes de embarcarnos en una aventura que puede ser costosa; simplemente evaluemos los entornos de explotación a los que nos dirigimos, dependencias externas (motores de bases de datos, componentes de terceros…), intención de reutilizar de código existente, las características que necesitamos y no están aún implementadas en Core, el tooling, y muchas otras cosas que nos podrían comprometer en el futuro. Eso sí, una vez la evaluación resulte positiva, seguro que disfrutamos con estos nuevos marcos de trabajo y las posibilidades que nos ofrecen :)

Por último, os dejo algunos enlaces por si queréis ampliar información:

Publicado en Variable not found.

» Leer más, comentarios, etc...

Variable not found

Por el aniversario de VariableNotFound, ¡O'Reilly te regala un libro!

June 28, 2016 08:30 AM

¡Seguimos dándolo todo con motivo del décimo aniversario de Variable Not Found! Acabamos de finalizar el último sorteo y ya vamos a por lo siguiente, que os adelanto que os va a encantar :)

Seguro que no necesitáis que os presente a O'Reilly, pues se trata de una de las compañías de referencia en la difusión de contenidos para desarrolladores en forma de libros, eventos y cursos en vídeo desde hace más de veinte años.

Pues bien, O'Reilly ofrece a los lectores de Variable not found descuentos del 40% en libros en papel, y de 50% en libros electrónicos y vídeo cursos utilizando el código PCBW al realizar la compra. Interesante propuesta, ¿eh?

Pero no acaba ahí la cosa... :)

O'Reilly quiere celebrar con todos nosotros el aniversario regalando a todos los lectores del blog un libro en formato electrónico, a elegir entre los siguientes diez títulos de programación, o un vídeo-tutorial sobre Web API.

Mastering Cross-Platform Development with Xamarin Mastering Cross-Platform Development with Xamarin
By Can Bilgin
Más info
C# 6 and .NET Core 1.0: Modern Cross-Platform Development C# 6 and .NET Core 1.0: Modern Cross-Platform Development
By Mark J. Price
Más info
jQuery Essentials jQuery Essentials
By Troy Miles
Más info
C# 6.0 in a Nutshell C# 6.0 in a Nutshell, Sixth Edition
By Joseph Albahari & Ben Albahari
Más info

CSS: The Missing Manual CSS: The Missing Manual, Fourth Edition
By David Sawyer McFarland
Más info
Learning NHibernate 4 Learning NHibernate 4
By Suhas Chatekar
Más info
Learning .NET High-performance Programming Learning .NET High-performance Programming
By Antonio Esposito
Más info
Code-First Development with Entity Framework Code-First Development with Entity Framework
By Sergey Barskiy
Más info
AngularJS: Up and Running AngularJS: Up and Running
By Shyam Seshadri, Brad Green
Más info
Concurrency in C# Cookbook Concurrency in C# Cookbook
By Stephen Cleary
Más info
RESTful Services with ASP.NET Web API Vídeo (2h): RESTful Services with ASP.NET Web API By Fanie Reynders
Más info

Tanto libros como vídeos son en inglés, pero supongo que esto no será impedimento para sacarles partido, ¿verdad? ;)

¿Y cómo podéis conseguir vuestro regalo?

Los que estéis interesados (¡todos, supongo! ;D) tenéis hasta el próximo 30 de junio de 2016 para obtener vuestro regalo. Sólo tenéis que lo siguiente:
  • Ayudarme a difundirlo para darle el mayor alcance posible, pues estaréis contribuyendo a que más personas puedan beneficiarse de la oferta del patrocinador. Por tanto, os agradecería mucho;

    • Que publiquéis en vuestra cuenta de Twitter, Facebook u otras redes sociales un enlace hacia este post. Por ejemplo, estaría bien algo como lo siguiente, aunque podéis demostrar vuestra creatividad y poner otras cosas siempre que vayan en la dirección de los objetivos propuestos :)
      Sólo hasta el 29 de junio, @oreillymedia te regala un e-book por ser seguidor de @variablnotfound. ¡Ve a por el tuyo! http://bit.ly/1Rhu7d4
    • Que publiquéis en vuestros blogs o páginas una breve reseña de esta iniciativa, con su enlace correspondiente a este post.
       
    • O, como mínimo, para los más perezosos, que retuiteéis en Twitter o compartáis en vuestras redes sociales los mensajes de otras personas que ya lo hayan publicado.
       
  • Si os apetece estar informados de las novedades del blog, seguir la nueva cuenta del blog en Twitter, @variablnotfound. A largo plazo pretendo que sea un canal exclusivo para el blog, separándolo de mi cuenta personal @jmaguilar.
      
  • Finalmente, reclamar vuestro libro o vídeo utilizando este enlace: http://oreil.ly/1W9VAFL. El proceso es muy simple: tendréis que registraros como usuario, elegir el contenido que os interese (uno por persona), y en pocas horas tendréis acceso al mismo.
Y por último, me gustaría agradecer a O'Reilly el interés mostrado por participar en esta celebración, y su impresionante contribución para hacerla aún más grande.

¡Que aproveche! Y seguid atentos al blog, porque adicionalmente todas las semanas estamos repartiendo regalos impresionantes :)

Publicado en Variable not found

» Leer más, comentarios, etc...

Variable not found

¡Últimos días para obtener tu libro gratis de O'Reilly!

June 27, 2016 01:45 PM

¡Consigue un libro gratis de O'Reilly!Pues casi ha pasado un mes desde que lanzamos esta iniciativa, y ya se cuentan por centenares los seguidores de Variable not found que han descargado su libro electrónico de O'Reilly, totalmente gratis.

Sólo quería recordaros que la promoción finaliza el próximo 30 de junio (no sé si ese día aún se podrá, así que, por si acaso, mejor que asumáis que no).

Por si no os enterasteis en su momento, estamos hablando de que para celebrar el aniversario del blog, O'Reilly regala a todos los lectores un libro en formato electrónico, a elegir entre estos diez títulos de programación, o un vídeo-tutorial sobre Web API:

Mastering Cross-Platform Development with Xamarin Mastering Cross-Platform Development with Xamarin
By Can Bilgin
Más info
C# 6 and .NET Core 1.0: Modern Cross-Platform Development C# 6 and .NET Core 1.0: Modern Cross-Platform Development
By Mark J. Price
Más info
jQuery Essentials jQuery Essentials
By Troy Miles
Más info
C# 6.0 in a Nutshell C# 6.0 in a Nutshell, Sixth Edition
By Joseph Albahari & Ben Albahari
Más info

CSS: The Missing Manual CSS: The Missing Manual, Fourth Edition
By David Sawyer McFarland
Más info
Learning NHibernate 4 Learning NHibernate 4
By Suhas Chatekar
Más info
Learning .NET High-performance Programming Learning .NET High-performance Programming
By Antonio Esposito
Más info
Code-First Development with Entity Framework Code-First Development with Entity Framework
By Sergey Barskiy
Más info
AngularJS: Up and Running AngularJS: Up and Running
By Shyam Seshadri, Brad Green
Más info
Concurrency in C# Cookbook Concurrency in C# Cookbook
By Stephen Cleary
Más info
RESTful Services with ASP.NET Web API Vídeo (2h): RESTful Services with ASP.NET Web API By Fanie Reynders
Más info

Además, O'Reilly ofrece a los lectores de Variable not found descuentos del 40% en libros en papel, y de 50% en libros electrónicos y video training utilizando el código PCVW al realizar la compra.

¿Y cómo podéis conseguir vuestro regalo?

Recordad que tenéis hasta el próximo 30 de junio de 2016 para obtener vuestro regalo. Sólo tenéis que lo siguiente:
  • Ayudarme a difundirlo para darle el mayor alcance posible, pues estaréis contribuyendo a que más personas puedan conseguir su regalo. Por tanto, os agradecería mucho:
              
    • Que lo comentéis con vuestros compañeros, amigos y conocidos que aún no se hayan beneficiado de esta iniciativa.
       
    • Que publiquéis en vuestra cuenta de Twitter, Facebook u otras redes sociales un enlace hacia este post. Por ejemplo, estaría bien algo como lo siguiente, aunque podéis demostrar vuestra creatividad y poner otras cosas siempre que vayan en la dirección de los objetivos propuestos :)
      Sólo hasta el 29-jun, @oreillymedia te regala un e-book por ser seguidor de @variablnotfound. ¡Ve a por el tuyo! http://bit.ly/295LSAJ
    • O, como mínimo, para los más perezosos, que retuiteéis en Twitter o compartáis en vuestras redes sociales los mensajes de otras personas que ya lo hayan publicado.
       
  • Si os apetece estar informados de las novedades del blog, seguir la nueva cuenta del blog en Twitter, @variablnotfound. A largo plazo pretendo que sea un canal exclusivo para el blog, separándolo de mi cuenta personal @jmaguilar.
     
  • Finalmente, reclamar vuestro libro o vídeo utilizando este enlace: http://oreil.ly/1W9VAFL. El proceso es muy simple: tendréis que registraros como usuario, elegir el contenido que os interese (uno por persona), y en pocas horas tendréis acceso al mismo.
¡¡No perdáis la oportunidad, que se acaba!!

Publicado en Variable not found

» Leer más, comentarios, etc...

Poesía Binaria

Cómo hacer login por Facebook en PHP paso a paso

June 27, 2016 08:04 AM

site_access

Hace unos años hice una serie de tutoriales (este, este y este, entre otros) para interactuar con Facebook. Con el tiempo, se han ido quedando antiguos. Han pasado muchas cosas y no he vuelto a revisarlos (además, han dejado de funcionar los antiguos métodos), por lo que he decidido, por fin, renovar toda aquella información.

Aunque esta información cambie con el tiempo, parece que Facebook ha llegado a un punto estable en el que no habrá cambios mayores en su API a no ser que se descubra una vulnerabilidad grave a nivel de diseño, aunque nunca podemos descartarlo.

Antes de nada

No me voy a meter en la forma en la que controláis vuestros sistemas de usuarios. Cada uno tiene implementado el suyo, o utiliza el que viene con su framework preferido, por lo que ese no será el cometido del post. Este post se dedicará únicamente a la creación de una aplicación en Facebook y su utilización para obtener un ID de usuario y un nombre, por lo que tendremos suficiente para hacer login en nuestra aplicación web en nombre del usuario.
Por otra parte, en el código del ejemplo, podemos encontrar clases o funciones temporales que deberán ser sustituidas en un proyecto definitivo ya que están hechas sólo para el ejemplo (clase Storage, por ejemplo).

Creación de la aplicación

Lo primero que tenemos que hacer es acceder a Desarrolladores de Facebook e identificarte. Ahí vamos a encontrar diversas opciones para gestionar nuestras aplicaciones, y lo primero que debemos hacer es crear nuestra aplicación. Para esta guía he puesto capturas de pantalla de las páginas por las que paso que, a junio de 2016 son válidas aunque no descarto que el flujo de trabajo cambie, de todas formas, la esencia será parecida (eso espero).

Para crear la aplicación, para ello, nos dirigimos a Mis Aplicaciones y después Añadir una nueva Aplicación
crea_app_paso1
Luego nos preguntará el tipo de aplicación, o más bien su plataforma, ya que en nuestro caso, quien interactuará con Facebook será una página web, elegiremos www:
Screenshot 22-06-2016-140650
Lo siguiente es darle un nombre a la aplicación. El nombre no debe coincidir con ninguna aplicación nuestra anterior:
Screenshot 22-06-2016-180646
Por último, tenemos que rellenar algunos datos básicos (completar un captcha y ver una pequeña intro que podemos saltar haciendo scroll hacia abajo y Skip):
site_create_data

Tengo la aplicación hecha, ¿ahora qué?

Tras realizar los pasos anteriores llegaremos a un Dashboard de la aplicación:
fb_app_dashboard
Lo importante aquí es el Identificador de la aplicación (o Application ID) y la clave secreta de la aplicación (o Application Secret) y que, será lo que tendremos que introducir en nuestro código.
Como recomendación, esta información se puede almacenar en base de datos si tu web maneja muchos credenciales de aplicaciones de Facebook, o es, por ejemplo un plugin de WordPress que el usuario debe configurar. Aunque, en otras muchas aplicaciones, introduciremos dichos datos en código, aunque para esto, lo ideal es utilizar un archivo de configuración de nuestra aplicación web, o un archivo PHP sólo para estos datos. El objetivo es que podamos tener diferentes datos en desarrollo y en producción y que si subimos el código de desarrollo, estos valores no se vean afectados, incluso el día de mañana, puede que tengamos varios proyectos utilizando el mismo sistema que tengan que ser aplicaciones separadas.

Por lo tanto, yo voy a hacer un pequeño archivo, llamado Config.php, que será una clase de la que puedo leer la configuración de la aplicación. Seguramente en tu aplicación lo hagas de otra forma mucho más completa, aquí sólo está lo justo para que funcione el ejemplo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace App;

class Config
{
  protected static $cfg = array('appId' => "xxxxxxxxxxxxx",
                'appSecret' => "XXXXXXXXXXXXXXXXXXXXXXXXXXXX");

  public static function get($ent)
  {
    if (isset(self::$cfg[$ent]))
      return self::$cfg[$ent];
    return null;
  }

}

Crear el directorio de proyecto e instalar composer

Desde hace un tiempo, el SDK de Facebook utiliza Composer para la gestión de paquetes y dependencias, por lo que debemos instalarlo en nuestro equipo. Podemos seguir las instrucciones para instalarlo, que vienen en la web. De todas formas, para que funcione el ejemplo, lo vamos a instalar en el mismo directorio de nuestro proyecto (no hagáis esto en producción). También cabe decir que por el hecho de utiliza composer, podemos actualizar la biblioteca de Facebook a menudo para estar siempre al día (con cuidado siempre, porque algunas veces cambian algo en el core y puede repercutir en nuestra aplicación).

$ mkdir testfblogin
$ cd testfb
$ wget wget https://getcomposer.org/composer.phar

Instalando el SDK de Facebook

El SDK será un conjunto de bibliotecas que nos ayudarán a interactuar con Facebook de una forma más o menos sencilla. Para instalarlo, utilizando composer, es tan fácil como hacer:

$ composer require facebook/php-sdk-v4

O para este ejemplo, como tenemos composer en el mismo directorio de la aplicación:

$ php composer.phar require facebook/php-sdk-v4

Para aprovechar el autoload de composer en nuestra aplicación, editaremos composer.json y lo dejaremos así:

1
2
3
4
5
6
7
8
9
10
{
    "require": {
        "facebook/php-sdk-v4": "^5.2"
    },
    "autoload": {
    "psr-4": {
        "App\\": "app/"
    }
    }
}

El objetivo es poder trabajar en el directorio app para poder introducir clases para trabajar en nuestro proyecto. Tras eso podemos hacer:

$ composer update

No actualizará ningún paquete (están recién descargados), pero sí que reescribirá los ficheros del autoload para que no tengamos problemas.

Código fuente

Ahora viene un poco de código fuente, debería funcionar tras copiar y pegar (y poner vuestros credenciales de aplicación en Config.php). Eso sí, debemos recordar que esto es sólo un ejemplo. Un sistema real será más complicado, tendrá más opciones y requerimientos propios del proyecto. Esto sería lo mínimo.

Vamos a crear el directorio app dentro del raíz de nuestra aplicación, su contenido será: Config.php (lo pondré de nuevo con alguna línea más que antes) y PoesiaBinaria.php. Lógicamente, en Config.php debéis rellenar vuestros datos de aplicación.

Config.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
namespace App;

class Config
{
  protected static $cfg = array('appId' => "xxxxxxxxxxxxxxx",
                'appSecret' => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
                'loginUrl' => "http://midoinio.com/facebook/login.php");

  public static function get($ent)
  {
    if (isset(self::$cfg[$ent]))
      return self::$cfg[$ent];
    return null;
  }
}

PoesiaBinaria.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<?php

namespace App;

class PoesiaBinaria
{
  protected $fb;
  protected $helper;
  protected $loggedUser;
  protected $name;
  protected $id;

  function __construct()
  {
    session_start();
    $this->name = (isset($_SESSION['name']))?$_SESSION['name']:false;
    $this->id = (isset($_SESSION['id']))?$_SESSION['id']:false;
  }

  public function facebookInit()
  {
    $appId = Config::get('appId');
    $appSecret = Config::get('appSecret');
    $this->fb = new \Facebook\Facebook([
                 'app_id' => $appId,
                 'app_secret' => $appSecret,
                 'default_graph_version' => 'v2.6',
                 ]);
    $this->helper = $this->fb->getRedirectLoginHelper();
  }

  public function getLogin()
  {
    $_SESSION['more'] ='';
    $permissions = array();
    $loginUrl = $this->helper->getLoginUrl(Config::get('loginUrl'), $permissions);
    header('Location: '.$loginUrl);
    echo $loginUrl;
    die();
  }

  public function login()
  {
    $this->facebookInit();
    try {
      $at = (isset($_SESSION['accessToken']))?$_SESSION['accessToken']:false;
      if ($at)
    {
      $_SESSION['more'] = "Tengo el access token de antes.";
      $at = unserialize($at);
    }
      if (!$at)
    $at = $this->helper->getAccessToken();
      if (!$at)
    $this->getLogin();

      $this->loggedUser = $this->fb->get('/me', $at);
      $gu = $this->loggedUser->getGraphUser();
      $this->name = $gu->getName();
      $this->id = $gu->getId();
      $_SESSION['name'] = $this->name;
      $_SESSION['id'] = $this->id;
      $_SESSION['accessToken'] = $at;
    } catch(\Facebook\Exceptions\FacebookResponseException $e) {
      $intento = (isset($_SESSION['try']))?$_SESSION['try']:0;
      if ($intento<5)
    {
      $_SESSION['try']=$intento+1;
      $this->getLogin();
    }
      echo 'Graph returned an error: ' . $e->getMessage();
      exit;
    } catch(\Facebook\Exceptions\FacebookSDKException $e) {
      echo 'Facebook SDK returned an error: ' . $e->getMessage();
      exit;
    }
    return true;
  }

  public function getLoggedUser()
  {
    return $this->loggedUser;
  }

  public function getName()
  {
    return $this->name;
  }
 
  public function getId()
  {
    return $this->id;
  }

  public function isLogged()
  {
    return ($this->id!=false);
  }

  public function logout()
  {
    if (isset($_SESSION['name']))
      unset($_SESSION['name']);
    if (isset($_SESSION['id']))
      unset($_SESSION['id']);
  }
};

Ahora, vamos a crear tres ficheros en el directorio raíz: index.php , login.php y logout.php (serán muy sencillos, para hacer llamadas a las funciones de la clase PoesiaBinaria.

index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
require 'vendor/autoload.php';

$poesia = new \App\PoesiaBinaria();

if ($poesia->isLogged())
  {
    echo "Identificado como usuario: ".$poesia->getName()."<br/>";
    echo "Tu ID de Facebook es: ".$poesia->getId()."<br/>";
    echo '<a href="logout.php">Cerrar sesi&oacute;n</a>';
    if (isset($_SESSION['more']))
      echo "<br/>Mensaje: ".$_SESSION['more'];
  }
else
  {
    echo "Usuario no identificado. Pulsa <a href=\"login.php\">aqu&iacute;</a> para entrar";
  }

login.php:

1
2
3
4
5
6
7
8
9
10
<?php
require 'vendor/autoload.php';

$poesia = new \App\PoesiaBinaria();

if ($poesia->login())
  {
    echo 'Logged in as ' . $poesia->getName(). "(".$poesia->getId().")";
    header('Location: index.php');
  }

logout.php:

1
2
3
4
5
6
7
<?php
require 'vendor/autoload.php';

$poesia = new \App\PoesiaBinaria();

$poesia->logout();
header('Location: index.php');

Proceso de identificación

Una vez subidos los ficheros a nuestro servidor entramos en nuestra página página principal. Se ejecutará nuestro fichero index.php y veremos lo siguiente:
testfb1
Claramente, aún no hemos iniciado el proceso de identificación y no se ha producido aún ninguna comunicación con los servidores de Facebook. Por ahora, todo se ha ejecutado en nuestro servidor, no tenemos ninguna sesión abierta y no nos hemos identificado aún.

Si pulsamos el enlace (que en nuestra web puede tener un icono de la red social, o cualquier cosa parecida), la primera vez que lo hagamos veremos esta pantalla:
testfb2
Aquí es cuando el usuario debe autorizar o no a Facebook para que envíe nuestros datos a la aplicación. Aunque sólo lo veremos la primera vez que realicemos la autentificación.

Tras aceptar, Facebook redirigirá a nuestra loginUrl (Ver archivo Config.php), aportará un código de autorización que utilizaremos para obtener el AccessToken (aunque la misma biblioteca de Facebook se encargará de ello). Nosotros, en login.php haremos la identificación del usuario y estableceremos los valores a las variables de sesión para permanecer identificados en nuestra aplicación. Tras ello, redirigiremos a index.php, en el que veremos lo siguiente:
testfb3
En este punto, podemos utilizar el ID de usuario de Facebook para identificar unívocamente al usuario. Si tenemos un sistema de identificación de usuarios paralelo y similar, por ejemplo, IDs de usuario en nuestro propio sistema (la identificación por Facebook puede ser un método adicional de identificación en nuestra web), podemos almacenar el ID de Facebook junto con los datos de usuario que ya tengamos.

Si pulsamos Cerrar sesión. Eliminaremos las variables de sesión del usuario (en nuestro servidor). Eso no tiene nada que ver con Facebook. Para este ejemplo he dejado el Access Token asociado a la sesión, de esta forma si volvemos a iniciar sesión veremos algo parecido:
testfb4
Aunque con un mensaje menos, como tenemos el Access Token podemos proporcionar una identificación más rápida al usuario ya que realizamos menos intercambio de datos. Es más, no realizamos la identificación directamente, ya que hacemos una petición de datos a Facebook directamente y estábamos autorizados previamente. Eso sí, si ocurre algún error aquí, como por ejemplo el AccessToken caducado o invalidado, sí que repetiríamos todo el proceso.

Podemos guardar los AccessTokens de los usuarios de Facebook para realizar acciones en nombre de los usuarios (por ejemplo enviar publicaciones cuando no están, subir fotos, etc. Todo puede ser utilizado para el bien (hacer la vida de las personas más fáciles) o para el mal… aunque Facebook se toma muy en serio las aplicaciones maliciosas y las persigue.

Cuestión de gustos

Cada vez más aplicaciones web permiten el registro y la identificación por Facebook. De esta forma nos ahorramos verificaciones, petición de datos y damos facilidad al usuario, ya que normalmente todos los usuarios de Facebook estamos identificados en la red social, sólo es pulsar un botón y autorizar la primera vez.

Aunque muchas páginas ofrecen dos opciones: registro e identificación por Facebook, podemos facilitar aún más la vida al usuario si proporcionamos la opción “Entrar por Facebook“. Es decir, la diferencia entre registrarnos e identificarnos es que en el primero escribimos en el registro de nuestro usuario y en el segundo leemos de él. Pero cuando entra en juego la identificación por Facebook el proceso de petición de datos es el mismo. Obtenemos los datos de Facebook de la misma forma, y con el ID de Facebook podemos saber si el usuario es nuevo o viejo. Con todo, podemos saber si es la primera vez que entra y realizar la petición y registro de información de forma totalmente transparente al usuario. Al final:

  • El usuario pulsa Entrar con Facebook
  • El usuario autoriza la aplicación
  • La aplicación comprueba si es la primera vez que entra:
    • Si es la primera vez, pide a Facebook los datos necesarios, crea registros en base de datos y establece la identificación del usuario
    • Si no es la primera vez, establece la identificación del usuario

Más cosas

Pronto, nuevos posts para realizar publicaciones y utilizar Facebook en nuestras propias aplicaciones web.

Foto principal (original): Sarah Stewart

The post Cómo hacer login por Facebook en PHP paso a paso appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 247

June 27, 2016 06:40 AM

Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

.NET

ASP.NET

.NET Core / ASP.NET Core

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Y para finalizar, ahí tenéis un interesante Podcast donde Bruno Capuano y Pedro J. Molina charlan sobre contenedores y Docker para dar sentido a esos ratos muertos que pasamos en el coche o en el metro cada día :)



Publicado en Variable not found

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

FileOptimizer 8

June 26, 2016 03:30 PM

FileOptimizer 8 lleva ya un tiempo entre nosotros, concretamente desde finales de 2015, sobre el que he ido aplicando ya 4 actualizaciones. Sin embargo desde Estadísticas de FileOptimizer, que nos os mantenía al corriente. La falta de tiempo, y porque no, también la creciente complejidad del proyecto, unido a que no hay colaboradores que ayuden [...]

» Leer más, comentarios, etc...

Variable not found

Ganadores del sorteo de componentes y herramientas de Telerik

June 26, 2016 10:36 AM

TelerikProbablemente haya cosas mejores que hacer un domingo por la mañana, pero pocas tan gratificantes como ir a votar y después ponerse a repartir regalos :)

Así que, siguiendo la tradición, nos hemos reunido un servidor y su habitual instancia de System.Random para echar en el bombo las papeletas virtuales y elegir al azar los ganadores del sorteo de licencias de la suite DevCraft Complete de Telerik.

Y hoy la suerte ha señalado a:

Carlos Gómez @devcfgc
Bilbao
Luis Felipe Gil @lamaslg
Madrid
¡Enhorabuena! En breve me pondré con contacto con vosotros para facilitaros vuestras licencias. Y muchas gracias a los que no habéis tenido tanta suerte, pero no desesperéis que todavía tendréis alguna oportunidad más :)

Me gustaría agradecer también a Telerik su gran apoyo a la celebración del aniversario del blog, que ha sido espectacular.

Ah, y mientras comenzamos el próximo sorteo, no olvidéis que por ser lectores del blog ¡aún podéis conseguir vuestro libro gratis de O'Reilly! Daos prisa porque el tiempo se acaba y en breve acabará la promoción :)

Pero seguid atentos al blog, porque el próximo será ya el último sorteo… ¿alguien había dicho que le gustaría tener una licencia de Resharper? ;)

Publicado en Variable not found

» Leer más, comentarios, etc...

Blog Bitix

El lenguaje de programación, framework y librerías importan

June 26, 2016 10:00 AM

Para programar hay una abundancia tremenda de lenguajes, librerías, frameworks, tecnologías, etc… disponibles para desarrollar un proyecto. Esto es muy bueno ya que podremos elegir la combinación de cualquiera de ellas que más se ajuste a las necesidades del proyecto, las que mejor conozcamos ya o según nuestras preferencias en base a sus características incluyendo su comunidad, documentación, si tiene un desarrollo activo, fecha de la última versión u otros motivos que consideremos. El lado malo de esta abundancia es que requiere analizar seguramente no todas pero al menos las más nombradas, más usadas, con mejor documentación o con un mantenimiento activo. Por la cantidad de opciones dicha tarea de análisis requiere tiempo y esfuerzo que no debe abrumarnos considerando que cualquiera de ellas vale.

Algunas personas piensan que las herramientas no son importantes quizá creen que hay tantas que da igual cualquiera de ellas o que solo importan las personas, «lo que hay entre el teclado y la silla». Entre varias herramientas adecuadas ciertamente en un proyecto no serán lo más importante ni usar alguna en concreto es un fin pero eso no quiere decir que no sean importantes. Son importantes porque afectan de forma notable al desarrollo del proyecto, por poner un ejemplo no es lo mismo un lenguaje o framework que evita errores de compilación en producción, un IDE que los detecta según se escribe el código o que permite hacer refactors con más garantías de no introducir errores que un lenguaje en el que necesitas teses que cubran la totalidad del código simplemente para detectarlos, no es lo mismo el número de lineas necesarias o su verbosidad pero es más importante la legibilidad si va a ser mantenido durante mucho tiempo, no es lo mismo elegir una herramienta ampliamente probada que una implementada por nosotros con el tiempo necesario a dedicar a desarrollarla y que probablemente finalmente sea menos flexible que otra existente, no es lo mismo una base de datos relacional que garantiza la integridad de los datos que una base de datos NoSQL sin validación de esquema. Yendo a un extremo creo que nadie considera siquiera usar ensamblador para hacer una aplicación web o usar Java, hasta el momento, para programar un sistema operativo de alto rendimiento que exprima el máximo potencial del hardware. Pero entre algunas opciones equivalentes cualquiera, con matices, nos servirá, por ejemplo, usar el lenguaje PHP, C# o Java para hacer una aplicación web usando para cada opción los frameworks Symfony, ASP.NET MVC o Apache Tapestry. Hay grados de lo adecuado que es una herramienta para una necesidad.

Por otro lado las herramientas consideradas en el inicio de un proyecto no son inmutables durante toda su existencia y cambian en la medida que las necesidades del proyecto cambian. En una startup al principio se necesitará una combinación de herramientas que permita probar la viabilidad del proyecto y evolucionar rápidamente el producto o servicio. Más tarde según se estabiliza el proyecto y crece surgirán nuevas necesidades como mayor fiabilidad, menos errores y escalabilidad tanto en cantidad de código y número de personas trabajando al mismo tiempo en el mismo código fuente.

También suele haber alguna discusión en si utilizar frameworks o no utilizarlos, usarlos evita tener que desarrollar nosotros mismos mucho código, nos ahorrará tiempo, tendremos mayor flexibilidad y menos errores pero usándolos el proyecto tendrá esa dependencia lo que implica que el código se deberá adaptar a él que aún así igual es algo que queremos para estructurar correctamente el código según el marco de trabajo ofrecido. Por otro lado he presenciado comentarios desfavoreciendo el uso de frameworks, la mayoría de programadores no tienen los conocimientos y tiempo de implementar su propia alternativa con la misma calidad y en la mayoría de los casos basta con reutilizar alguna que cubra la necesidad y más importante esté ampliamente probada.

Para mi lo importante es que para cualquier librería o framework que elijamos tengamos en un futuro la posibilidad de reemplazarlo sin estar encadenados a él y sin tener que reescribir el proyecto entero, esto forma parte de las más básicas buenas prácticas de desarrollo, precisamente las aplicaciones que se desarrollan en capas y los frameworks que separan modelo, de vista, de controlador tratan de minimizar ese impacto.

Cada proyecto es distinto y hay que conocer sus requerimientos para seleccionar las herramientas que contribuyan al éxito o a la menor cantidad de dificultades, si se tratan de un proyecto en la plataforma Java probablemente varias herramientas serán las que indico en el artículo herramientas para un proyecto Java. Si no está clara la plataforma también puedes echarle un vistazo a 10 razones para seguir usando Java y novedades y nuevas características de Java 8.

La tecnologías, lenguajes, librerías, frameworks, … son herramientas a usar para conseguir un fin que es hacer realidad el proyecto, producto o servicio con un componente informático, las herramientas no son un fin en si mismo, no son lo más importante, lo más importante es resolver la necesidad de alguien normalmente con restricciones de tiempo y coste, pero desde luego no son irrelevantes y no da igual usar cualquiera. Son las herramientas equivalentes de un fontanero, pintor, carpintero u otros profesionales que tienen cantidad de ellas para realizar multitud de tareas específicas de forma efectiva y rápida junto con su conocimiento y experiencia. Los lenguajes de programación, frameworks y librerías de no ser importantes no existirían tantas incluso varias con diferentes propiedades para la misma necesidad.

» Leer más, comentarios, etc...

Variable not found

VariableNotFound cumple diez años, ¡y lo vamos a celebrar!

June 26, 2016 09:11 AM

¡10 años de VariableNotFound!Pues sí, amigos, ¡diez añazos! Mucho más de lo que habría podido imaginar en aquellos tiempos en los que Windows XP era el rey del escritorio, nadie había oído hablar de Twitter o Facebook y no existían los smartphones tal y como hoy los conocemos. Tiempos en los que decidí subirme al tren y empezar a escribir sobre cosas que iba aprendiendo y que pensaba que podría ser de utilidad a más gente.

Diez años después, con más de ochocientas cincuenta entradas, cerca de 2.000 comentarios publicados, y acercándonos a los dos millones de páginas vistas, si hay algo que tengo claro es que esto no habría sido posible sin vosotros, queridos lectores y amigos de la Variable. Muchas gracias a todos por estar ahí durante todos estos años, por vuestras visitas, vuestras aportaciones y sugerencias, y por permitirme seguir aprendiendo de vosotros cada día.

Y como desde pequeñito me enseñaron que en este mundo hay que ser agradecido, lo mejor que puedo hacer es celebrar este grato acontecimiento con todos vosotros :)

Así que, contando con el increíble apoyo de compañías de primera línea que han decidido sumarse a esta fiesta de celebración, durante las próximas semanas vamos a realizar sorteos de productos y servicios que seguro os entusiasmarán :)

CampusMVP  JetBrains  Telerik  Grapecity 
O'Reilly Media  Microsoft
  DevExpress

Estad atentos al blog, que ¡cada semana repartimos regalos!

En curso:

Sorteos ya finalizados:

El blog: las cifras del año pasado

Y dicho todo lo anterior, ya sabéis que me gusta siempre hacer un breve repaso de la evolución del blog durante el año pasado, así que, para los curiosos, ahí va.

Siguiendo en la tónica de los últimos años, continuamos lo que ya el año pasado denominé como una fase de leve crecimiento sostenido. Según las analíticas de Google, nos visitaron 150.000 usuarios (+6%), 272.000 páginas vistas (+0,64%), con un promedio de tiempo de estancia de 03m48s (+5%). En la página de Facebook superamos los 800 amigos (+7%), y en Twitter superamos los 1415 seguidores (+13%).

El oráculo de Google dice que la mayoría sois hombres (83%), aunque curiosamente este dato ha descendido un 7% en el último año, principalmente de entre 25 y 34 años (50%), profesionales de internet, tecnófilos, aficionados al cine y TV, entusiastas de los móviles y de los deportes (fútbol, principalmente).

BrowsersChrome sigue siendo el navegador más usado para acceder a los contenidos, con más del 73% de los usuarios. Respecto al año pasado, siguen cayendo Firefox (16%) y IE (6%). El nuevo Edge no supera el 1%. El 92% de vosotros usáis Windows, siendo Mac el segundo más utilizado con el 3%. Curiosamente, el 50% lo hacéis desde Windows 7, el 23% desde Windows 8.1, y algo más del 16% estáis ya utilizando Windows 10.

Tras varios años de incremento de visitas procedentes del otro lado del Atlántico, el origen de las visitas está prácticamente igualado ya entre España (22%) y Mexico (21%). Algo detrás, pero también in crescendo, tenemos Colombia (11%), Perú (8%), Argentina (7%) y Chile (6%).

Como es habitual, el 83% de las visitas proceden de los buscadores, Google en más del 99% de las ocasiones. El acceso directo, introduciendo la URL o desde favoritos, se utiliza el 10% de las ocasiones, y apenas un 4% de enlaces desde otros sitios web.

Y respecto a la pregunta que me han hecho tantas veces: "¿Y realmente te vale la pena? ¿Qué sacas tú de esto?" La respuesta sigue siendo una afirmación categórica, por supuesto que vale la pena. La satisfacción que supone escribir sobre lo que me gusta y pensar que esto puede ser útil a alguien es inigualable, y los grandes amigos que voy haciendo a lo largo de este camino no tienen precio. Sólo esto ya compensa al 100% el esfuerzo que supone mantener un blog tanto tiempo.

Pero dejando los intangibles aparte, también aporta otro tipo de beneficios más terrenales, aunque no por el lado de la publicidad, que es el que parecería obvio: Adsense sigue básicamente en su tónica; los ingresos me permiten invitar a mi familia a almorzar un par de veces al año, pero decididamente esto no va a ayudarme a liquidar la hipoteca ;D Ni rastro tampoco de los posts patrocinados de antaño, ni de anunciantes fijos que sí disfruté hace algunos años ya.

Los beneficios son indirectos y llegan en forma de visibilidad y oportunidades profesionales que de otra forma no habrían sido posibles. Por tanto, os puedo decir de primera mano que realmente un blog no sólo os podría ayudar a encontrar empleo; si prestáis servicios profesionales de cualquier tipo, vuestra bitácora puede seros incluso de más utilidad que contratar una valla publicitaria en vuestra autopista favorita ;D

Eso sí, también os puedo decir que en ningún caso, al menos de los que conozco, se trata de un retorno inmediato: se requieren años para llegar a este punto, y de hecho lo más habitual es que se caiga por el camino antes de conseguirlo. Pero sinceramente, no es nada que con un poco de paciencia y tesón no pueda conseguirse, así que os animo a lanzaros de forma decidida, que seguro que vuestro yo del futuro os lo agradecerá ;)

Y finalmente, aprovecho estas últimas líneas para agradeceros de nuevo vuestro incondicional apoyo durante todo este tiempo, y espero que sigáis por aquí muchos años más, ayudándome a buscar la Variable.

Publicado en Variable not found.

» Leer más, comentarios, etc...

Blog Bitix

Combinación de teclas para copiar y pegar en la terminal

June 24, 2016 01:30 PM

Linux
GNU

Usar una combinación de teclas para realizar alguna acción es más rápido que usar el ratón. Si se trata de una acción que realizamos frecuentemente podemos ahorrar bastante tiempo. Yo trabajo bastante con la terminal de GNOME y hasta ahora no sabía cómo copiar y pegar con una combinación de teclas del teclado.

La combinación de teclas estandarizada para copiar y pegar en cualquier aplicación tanto en Linux como en Windows es Ctrl+c para copiar y Ctrl+v para pegar de y al portapapeles. En la terminal (al menos en la de GNOME) cambia ligeramente y hay que usar Ctrl+Shift+c para copiar y Ctrl+Shift+v para pegar el texto en la posición del cursor.

Con el ratón deberemos seleccionar el texto pero con la combinación de teclas nos evitaremos pulsar el botón derecho del ratón, desplazarnos hasta la opción Copiar del menú y finalmente hacer clic en él, para pegar la acción usaremos el mismo menú pero pulsando en la opción Pegar.

Menú para copiar y pegar en la terminal de GNOME

Esto no es algo nada vital pero si es algo que usamos frecuentemente puede hacernos más fácil la tarea y ahorrarnos tiempo al igual que conocer y usar los atajos de teclado básicos de la terminal en GNU/Linux.

» Leer más, comentarios, etc...

Picando Código

¡Felices 20 años Nintendo 64!

June 23, 2016 05:00 PM

Nintendo 64Hoy hace 20 años del lanzamiento del Nintendo 64 en Japón. Aprovecho la oportunidad para celebrar esta consola que tantos ratos de diversión nos dió y sigue dando.

Los primeros datos de la nueva consola de Nintendo llegaban por la revista Club Nintendo  en esos tiempos. Ahí veíamos desde los inicios las características del Ultra 64, nombre que fue cambiado a Nintendo 64 antes de su lanzamiento oficial. Mostraban fotos de prototipos, presentaciones en distintos eventos de videojuegos y tecnología, y potenciales juegos.

El control parecía demasiado grande en las fotos y la transición a 3D de Mario y otros personajes de la familia no terminaba de convencer. Pero todo cambió cuando pudimos probarlo.

Nintendo 64

Tengo grabada en mi memoria la primera vez que usé un Nintendo 64. Estaba con mi familia recorriendo el centro de la ciudad de Maldonado. Pasamos caminando por enfrente al local de electrodomésticos de los padres de un amigo y ahí lo vi en un stand en la vidriera. Un Nintendo 64 conectado a un televisor con el juego Super Mario 64. Dejé que mi familia siguiera camino y me quedé ahí a mirar a través de la vidriera.

Enseguida confirmé que la transición de Mario a 3D había sido un éxito. Los gráficos súper coloridos y el castillo en 3D, con los árboles, el agua, y demás detalles se veían espectaculares. Al rato sale del comercio (creo que) la madre de mi amigo, me saluda y me pregunta “¿Querés entrar a probarlo?”. Me encantaría poder ver mi cara en ese momento. Obviamente dije que sí, y entré a jugar Super Mario 64.

Al pararme del lado de adentro de la vidriera frente al stand me detuve unos segundos a admirar la consola. Antes de agarrar el control lo examiné con la mirada un rato. El miedo de que fuera demasiado grande como mostraban las fotos desapareció enseguida. Y al levantarlo para empezar a jugar se sintió súper cómodo y distinto a todo lo que había venido antes. Así estuve un buen rato jugando hasta que mi familia me encontró y tuve que irme. Obviamente volví a jugar con este amigo varias veces, recuerdo también haber probado Wave Race 64 y sorprenderme con los gráficos del agua de esa época.

Estuve muchos años jugando Nintendo 64 en lo de amigos. La primera vez que jugué Starfox 64 también me quedó bastante grabada. Mi primo me invitó a la casa de uno de sus amigos que además de tener un Nintendo 64 había adquirido recientemente el juego. Nos encantó, pasamos horas jugando esa tarde, y llegamos a vencer a Andross.

Hubo un verano en el que me prestaron un Nintendo 64 que no usaban mucho. Tenía los juegos Perfect Dark y The Legend Of Zelda: Ocarina Of Time, entre otros. Además de terminar la aventura de Ocarina of Time, ese verano pasé noches enteras jugando Perfect Dark multiplayer. Estos dos juegos, además de ser de los mejores que dió la consola, siguen siendo de mis favoritos.

Nintendo 64 juegos

Otro título que consumió muchas horas de mi vida fue Mario Kart 64. La fórmula había sido exitosa en el Super Nintendo, pero la versión en 64 fue la definitiva en su momento. Incluso recuerdo en épocas del blog postear de fines de semana enteros jugando y compitiendo multiplayer en los campeonatos y modo batalla. Todavía hoy es un excelente juego en el que desafiar a otras personas.

Eventualmente pude ahorrar hasta adquirir un Nintendo 64 y desde entonces ha estado prácticamente siempre conectado a mi televisor. Lo genial de su biblioteca de juegos es que hay varios juegos para disfrutar solo como Super Mario 64, Starfox 64 y The Legend Of Zelda: Ocarina Of Time. Pero cuando se trata de jugar con más gente, Mario Kart 64, Smash Bros. 64, Perfect Dark (y/o Goldeneye) eran insuperables.

Últimamente el juego que más he jugado es F-Zero X. Lo descubrí medio tarde, pero requiere bastante habilidad y tiempo dominarlo. Por eso como desafío es bastante entretenido, y es un buen juego para medir lo gastado de las palanquitas de los controles del Nintendo 64. Por suerte hay esperanza para esas palanquitas rotas, veremos qué tal terminan estos proyectos que intentan proveer una solución.

Después de tantos años Nintendo sigue apostando a innovar en el área de videojuegos. Su éxito con Wii fue increíble, y si bien no lograron lo mismo con Wii U, habrá que ver cómo innovan con su próxima consola nombre clave Nintendo NX.

Gracias Nintendo 64 por tantas horas de escape a otros mundos y diversión. Espero que mi querido 64 siga funcionando por 20 años más.
Me dieron ganas de jugar…

Nintendo 64

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

Clipper y C

June 23, 2016 07:32 AM

A nivel informático, recuerdo con mucho cariño, la época de principios de los años 90. En aquel momento, bastaba con saber lenguaje C y Clipper. MS-DOS 3.30 era el sistema operativo más difundido, acababa de lanzarse DR-DOS 5 y MS-DOS 5 mientras que MS-DOS 6 y DR-DOS 6.0, estaban aún por salir. Se usaba Windows [...]

» Leer más, comentarios, etc...

Poesía Binaria

Redimensionando fotos en PHP evitando que se deformen nuestras imágenes

June 22, 2016 08:44 AM

photo-1464621922360-27f3bf0eca75
En las webs modernas se intenta que el usuario sea capaz de hacer casi de todo. Eso sí, siempre que de cara al servidor sea seguro. Por ejemplo, de nada vale que un usuario pueda generar a través de una web 1000000 de decimales del número PI si mientras tanto ningún usuario más es capaz de hacer nada.
Una de las tareas básicas de una web hoy e día es redimensionar un foto. Es decir, adaptar el tamaño de una foto para adecuarla a nuestras necesidades. Lo primero que tenemos que pensar es que a la hora de transmitir imágenes por la red, tenemos que evitar enviar archivos demasiado grandes. Por ejemplo, si tenemos que mostrar una imagen como máximo a 500×500, debemos evitar enviar la imagen a 4096×4096 ya que no vamos a mostrarla tan grande, vamos a desperdiciar ancho de banda nuestro enviando la foto y tiempo del usuario descargándola.
Todo eso sumado al auge de las webs dinámicas que deben permitir la subida de archivos de imagen al usuario (o al administrador) y de forma sencilla adaptarlas a la web. De forma que se pueda subir una foto directamente de la cámara digital y a la hora de visualizarla en la web quedarnos sólo con el tamaño o los tamaños que necesitemos.

Aunque, como siempre, tenemos varias formas de hacer las cosas, y, sobre todo, hay un factor que debemos tener en cuenta: el aspecto de la foto.

Aspecto de una imagen

El aspecto de una imagen no es más que la relación entre anchura y altura. Vamos, ancho partido por alto. Si os fijáis, es lo mismo que se utiliza en las pantallas. Ahora es común que las pantallas sean 16:9 (panorámicas, que son mucho más anchas que altas), antiguamente los monitores solían ser 4:3 (no eran cuadrados, pero casi). No obstante hay muchas relaciones de aspecto estándar para monitores, proyección, etc.
Cuando hablamos de imágenes, puede haber tantas relaciones de aspecto como imágenes, ya que las fotos podemos recortarlas de mil maneras, y tanto anchura como altura pueden tomar casi cualquier valor y su relación de aspecto se suele expresar como el resultado de la división entre ancho y algo. Si nuestra foto tiene una resolución de 320×240 su relación será 1,33 (¡ anda ! 4/3 da también 1,33 y es que esta imagen se podrá presentar a pantalla completa sin que se observe ninguna deformación), si nuestra foto tiene de dimensiones 600×500 la relación será de 1,2 y si la ponemos a pantalla completa en un monitor 4:3 la veremos deformada.

Dejo aquí la foto original con una resolución de 1280×792 y una relación de aspecto de 1,61:
baterias

Sobre PHP y Frameworks

Si estás trabajando con un framework o una biblioteca especializada en imágenes, seguramente dispongas de funciones o métodos para realizar estas operaciones de forma directa y con algunas opciones más. Pero si te gusta programar PHP a pelo, aquí encontrarás algunas guías que podrán ser útiles para tus proyectos. Aunque podemos utilizar otras bibliotecas para gráficos en PHP, como por ejemplo ImageMagick, estos ejemplos se han hecho utilizando GD.

Las funciones que utilizaré aquí serán sencillas, porque sobre todo el post va encaminado a la matemática de la transformación de las dimensiones y el recorte de la foto.

Redimensionado rápido y directo

Lo que hacemos aquí es cambiar el tamaño de la foto. Nos da igual la relación de aspecto, cogeremos una foto (baterias.jpg) y sean cuales sean sus dimensiones, las cambiaremos.
Para ello utilizaremos imagecopyresampled(), eso sí, si no tenemos cuidado con la resolución que pongamos, la imagen puede quedar deformada.
Si tomamos este código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php

$imagefile = 'baterias.jpg';

/**
 * Opens new image
 *
 * @param $filename
 */

function icreate($filename)
{
  $isize = getimagesize($filename);
  if ($isize['mime']=='image/jpeg')
    return imagecreatefromjpeg($filename);
  elseif ($isize['mime']=='image/png')
    return imagecreatefrompng($filename);
  /* Add as many formats as you can */
}

/**
 * Simple image resample into new image
 *
 * @param $image Image resource
 * @param $width
 * @param $height
 */

function simpleresize($image, $width, $height)
{
  $new = imageCreateTrueColor($width, $height);
  imagecopyresampled($new, $image, 0, 0, 0, 0, $width, $height, imagesx($image), imagesy($image));
  return $new;
}

$imgh = icreate($imagefile);
$imgr = simpleresize($imgh, 520, 200);

header('Content-type: image/jpeg');
imagejpeg($imgr);

La imagen resultante será:
baterias_500_520_simple
Y, como no hemos respetado la relación de aspecto de la pantalla, la imagen sale deformada, las baterías salen como aplastadas. Esto nos puede servir para imágenes muy pequeñas, o para cuando sepamos (o no nos importe) que la imagen no va a sufrir una deformación.

Una dimensión fija

Si no queremos que la imagen sufra ninguna deformación, lo que podemos hacer es dejar una dimensión fija. Si dejamos el ancho fijo, con la relación de aspecto de la imagen original podemos calcular la nueva altura, y si dejamos la altura fija, podemos calcular la anchura. Siguiendo las siguientes ecuaciones:
ancho_alto
El código sería el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?php

$imagefile = 'baterias.jpg';

/**
 * Opens new image
 *
 * @param $filename
 */

function icreate($filename)
{
  $isize = getimagesize($filename);
  if ($isize['mime']=='image/jpeg')
    return imagecreatefromjpeg($filename);
  elseif ($isize['mime']=='image/png')
    return imagecreatefrompng($filename);
  /* Add as many formats as you can */
}

/**
 * Resize maintaining aspect ratio
 *
 * @param $image
 * @param $width
 */

function resizeAspectW($image, $width)
{
  $aspect = imagesx($image) / imagesy($image);
  $height = $width / $aspect;
  $new = imageCreateTrueColor($width, $height);

  imagecopyresampled($new, $image, 0, 0, 0, 0, $width, $height, imagesx($image), imagesy($image));
  return $new;
}

/**
 * Resize maintaining aspect ratio
 *
 * @param $image
 * @param $height
 */

function resizeAspectH($image, $height)
{
  $aspect = imagesx($image) / imagesy($image);
  $width = $height * $aspect;
  $new = imageCreateTrueColor($width, $height);

  imagecopyresampled($new, $image, 0, 0, 0, 0, $width, $height, imagesx($image), imagesy($image));
  return $new;
}

$imgh = icreate($imagefile);
$imgr = resizeAspectH($imgh, 520);

header('Content-type: image/jpeg');
imagejpeg($imgr);

Donde podemos cambiar la llamada a resizeAspectW() por resizeAspectH() dándonos como resultado las siguientes imágenes:

baterias_resized_w
520×321
baterias_resized_h
840×520

Mantener aspecto sin pasarse de dimensiones

El problema con el algoritmo anterior es que las dimensiones pueden crecer mucho. Sobre todo si permitimos que el usuario nos suba fotografías, pueden subir una foto alargada de dimensiones 1×10000 (aspecto 0,0001) si queremos fijar el ancho a 200 la altura saldría a 2000000 lo que es inviable. Por tanto, debemos controlar cuánto crece la imagen. Podemos seguir este código que fijará las dimensiones máximas a las que vamos a tener la imagen resultante. La relación de aspecto se mantendrá y no se superarán las dimensiones fijadas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php

$imagefile = 'baterias.jpg';

/**
 * Opens new image
 *
 * @param $filename
 */

function icreate($filename)
{
  $isize = getimagesize($filename);
  if ($isize['mime']=='image/jpeg')
    return imagecreatefromjpeg($filename);
  elseif ($isize['mime']=='image/png')
    return imagecreatefrompng($filename);
  /* Add as many formats as you can */
}

/**
 * Resize image maintaining aspect ratio, occuping
 * as much as possible with width and height inside
 * params.
 *
 * @param $image
 * @param $width
 * @param $height
 */

function resizeMax($image, $width, $height)
{
  /* Original dimensions */
  $origw = imagesx($image);
  $origh = imagesy($image);

  $ratiow = $width / $origw;
  $ratioh = $height / $origh;
  $ratio = min($ratioh, $ratiow);

  $neww = $origw * $ratio;
  $newh = $origh * $ratio;

  $new = imageCreateTrueColor($neww, $newh);

  imagecopyresampled($new, $image, 0, 0, 0, 0, $neww, $newh, $origw, $origh);
  return $new;
}

$imgh = icreate($imagefile);
$imgr = resizeMax($imgh, 400, 200);

header('Content-type: image/jpeg');
imagejpeg($imgr);

La imagen resultante ahora será (323×200):
baterias_resized_max
Os invito a probar este algoritmo con otras dimensiones de imagen para ver cómo se comporta.

Redimensiona y recorta (resizeCrop)

En el caso anterior, una dimensión sí que quedará fija (se elegirá en función de la relación de aspecto), pero, si queremos que las dos dimensiones queden fijas sin que se pierda la relación de aspecto, lo que debemos hacer es recortar la imagen. De esta forma perderemos información, pero la foto se seguirá viendo bien, aunque deberíamos decidir de dónde perdemos información, ya que si la imagen resultante es más alta que la deseada, debemos perder información vertical y si es más ancha horizontal.
Podemos seguir el siguiente algoritmo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php

$imagefile = 'baterias.jpg';

/**
 * Opens new image
 *
 * @param $filename
 */

function icreate($filename)
{
  $isize = getimagesize($filename);
  if ($isize['mime']=='image/jpeg')
    return imagecreatefromjpeg($filename);
  elseif ($isize['mime']=='image/png')
    return imagecreatefrompng($filename);
  /* Add as many formats as you can */
}

function resizeCrop($image, $width, $height, $displ='center')
{
  /* Original dimensions */
  $origw = imagesx($image);
  $origh = imagesy($image);

  $ratiow = $width / $origw;
  $ratioh = $height / $origh;
  $ratio = max($ratioh, $ratiow); /* This time we want the bigger image */

  $neww = $origw * $ratio;
  $newh = $origh * $ratio;

  $cropw = $neww-$width;
  /* if ($cropw) */
  /*   $cropw/=2; */
  $croph = $newh-$height;
  /* if ($croph) */
  /*   $croph/=2; */

  if ($displ=='center')
    $displ=0.5;
  elseif ($displ=='min')
    $displ=0;
  elseif ($displ=='max')
    $displ=1;

  $new = imageCreateTrueColor($width, $height);

  imagecopyresampled($new, $image, -$cropw*$displ, -$croph*$displ, 0, 0, $width+$cropw, $height+$croph, $origw, $origh);
  return $new;
}

$imgh = icreate($imagefile);
$imgr = resizeCrop($imgh, 520, 500, 0.4);

header('Content-type: image/jpeg');
imagejpeg($imgr);

La imagen resultante será (520×500):
baterias_resized_crop
El cuarto argumento, $displ podrá tener uno de los siguientes valores:

  • ‘min': recortará la imagen arriba o a la izquierda
  • ‘center': se quedará con la parte central de la imagen
  • ‘max': recortará la imagen abajo o a la derecha
  • 0>=x>=1 (cualquier valor entre 0 y 1): desplazará la ventana de recorte hacia la derecha o abajo. Podemos interpretarlo como un porcentaje.

Rotar y recortar

Si queremos aplicar un efecto chulo a nuestras fotos, podemos rotarlas unos grados. El problema es que se crearán unos bordes negros (también podemos hacerlos transparentes), pero nos incomodarán. Así que, vamos a proceder a buscar la región cuadrada más grande de imagen sin bordes y recortar la imagen con esas dimensiones en esa posición (primero redimensiono la imagen para hacerla más cómoda para trabajar):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?php

$imagefile = 'baterias.jpg';

/**
 * Opens new image
 *
 * @param $filename
 */

function icreate($filename)
{
  $isize = getimagesize($filename);
  if ($isize['mime']=='image/jpeg')
    return imagecreatefromjpeg($filename);
  elseif ($isize['mime']=='image/png')
    return imagecreatefrompng($filename);
  /* Add as many formats as you can */
}

/**
 * Resize image maintaining aspect ratio, occuping
 * as much as possible with width and height inside
 * params.
 *
 * @param $image
 * @param $width
 * @param $height
 */

function resizeMax($image, $width, $height)
{
  /* Original dimensions */
  $origw = imagesx($image);
  $origh = imagesy($image);

  $ratiow = $width / $origw;
  $ratioh = $height / $origh;
  $ratio = min($ratioh, $ratiow);

  $neww = $origw * $ratio;
  $newh = $origh * $ratio;

  $new = imageCreateTrueColor($neww, $newh);

  imagecopyresampled($new, $image, 0, 0, 0, 0, $neww, $newh, $origw, $origh);
  return $new;
}

function rotateCrop($image, $deg)
{
  $width = imagesx($image);
  $height = imagesy($image);

  $long = max($width, $height);
  $short = min($width, $height);

  $radians = deg2rad($deg);
  $_sin = abs(sin($radians));
  $_cos = abs(cos($radians));

  if ($short <= 2*$_sin*$_cos*$long)
    {
      $x = 0.5*$short;
      if ($width>$height)
    {
      $neww = $x/$_sin;
      $newh = $x/$_cos;
    }
      else
    {
      $neww = $x/$_cos;
      $newh = $x/$sin;
    }
    }
  else
    {
      $_cos2 = $_cos*$_cos - $_sin*$_sin;
      $neww = ($width*$_cos - $height*$_sin)/$_cos2;
      $newh = ($height*$_cos - $width*$_sin)/$_cos2;
    }

  $rot = imagerotate($image, $deg, 0);
  $new = imageCreateTrueColor($neww, $newh);

  imagecopy($new, $rot, 0,0,  imagesx($rot)/2-$neww/2 , imagesy($rot)/2-$newh/2 ,$neww, $newh);
  return $new;

}

$imgh = icreate($imagefile);
$imgr = resizeMax($imgh, 520, 200);
$imgv = rotateCrop($imgr, 30);
header('Content-type: image/jpeg');
imagejpeg($imgv);

El resultado sería algo como esto:
baterias_resized_rotcrop

Foto principal: Tony Webster

The post Redimensionando fotos en PHP evitando que se deformen nuestras imágenes appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Koalite

Ni titulitis, ni cuñadismo

June 20, 2016 03:22 PM

Yo soy Ingeniero Superior en Informática y estoy orgulloso de ello. Terminé la carrera en el año 2001, después de 5 años en los que aprendí muchas cosas, algunas más útiles y otras menos, pero nunca me he arrepentido del tiempo y el esfuerzo que dediqué a ello.

Si cuento esto es porque la semana pasada hubo cierto revuelo con la campaña Informática Solución YA, en la que algunas asociaciones de Ingenieros Informáticos volvieron a reclamar una regulación para nuestro sector y, como ingeniero que puede ser regulado, creo que no está de más expresar mi opinión.

Titulitis no, gracias

Que el sector de la informática tiene muchos problemas no es nuevo. Precisamente hace poco me quejaba de que lo peor de desarrollar software es tener que tratar con empresas y desarrolladores muy poco profesionales.

¿Es la solución que el estado regule quién se puede dedicar a desarrollar software y en que condiciones? Rotundamente, no.

Para empezar, no creo que la intervención estatal, en general, sea una buena salida para casi nada, y creo que debería ser siempre lo más limitada posible.

Soy consciente de que ese es un argumento que tiene unas implicaciones mayores con las que no todo el mundo estará de acuerdo, por lo que no voy a ahondar en él, sino que me voy a centrar en aspectos más prácticos.

Se supone que uno de los objetivos de la regulación es garantizar a los consumidores que el software que se produce tiene la calidad adecuada, y de alguna manera se asume que la cualificación necesaria para desarrollar software de calidad es algo que se puede medir con un título.

Ójala fuese así. Sería mucho más sencillo encontrar empresas adecuadas a las que encargarles proyectos de desarrollo.

La realidad es que tener un título no garantiza nada más allá de haber aprobado x exámenes. De hecho, puedes tener un título de ingeniero informático y no haber ejercido como tal en tu vida (y conozco más de un caso): ¿esa persona está más o menos preparada para desarrollar una aplicación que alguien que se dedica a ello continuamente durante 10 años?

Las reivindicaciones se basan en títulos (porque para eso son colegios de Ingenieros), pero supongamos que cambiamos un título por una certificación. Por un examen o un permiso renovable, como el carnet de conducir, pero de desarrollador de aplicaciones. ¿Tiene sentido? ¿Quién va a establecer el contenido del examen de certificación? ¿Cada cuánto tiempo se va a renovar? ¿Hay uno genérico o depende del tipo de aplicación? ¿De verdad esto nos lleva a alguna parte?

Me vais a disculpar, porque seguro que soy un mal pensado, pero a mi todo esto de regular me suena a pretender adquirir unos privilegios. Una regulación del sector sería más útil para los ingenieros que para los clientes y usuarios de aplicaciones informáticas, y me parece mal que el estado regule de esa manera.

Pero hay que valorar el conocimiento

Cuando se entra en estos temas se corre el riesgo de pasar de un extremo al otro. Del elitismo de “si no eres ingeniero no puedes dedicarte a esto” al “estudiar una carrera no sirve para nada, lo que cuenta es la experiencia”.

Es fácil encontrar artículos en los que se califica estudiar una carrera como una gran pérdida de tiempo, y muchas veces se tiende a valorar certificaciones y cursos que nos permitan ponernos al día rápidamente en las cosas que de verdad se usan mucho más que el conocimiento profundo, de carácter más teórico, que puedes alcanzar con otro tipo de formación.

Estudiar una carrera, al igual que cualquier otro tipo de formación, no garantiza que aprendas nada. Para eso necesitas dar con unos profesores no demasiado malos (tampoco hace falta que sean excepcionalmente buenos) y poner bastante de tu parte.

En una carrera se enseñan muchas cosas que, a priori, no sirven para nada, pero que luego resultan ser la base de muchas de esas cosas que se enseñan en los cursos que permiten ponerte al día rápidamente en la tecnología de turno. Si no conoces esos fundamentos, acabarás volviéndolos a estudiar muchas veces en otros tantos cursos distintos, bajo nombres diferentes.

No hay nada que te impida aprender por tu cuenta lo mismo que se enseña en una carrera, pero en general te va a costar más. Siempre es más complicado aprender sólo que aprender guiado. Eso lo saben hasta los artesanos, con sus maestros y aprendices.

Un título no garantiza que se hayan adquirido esos conocimientos fundamentales, pero tener 10 años de experiencia tampoco garantiza nada. Puedes tener 10 años de experiencia y no tener ni idea de desarrollar software. Y puedes tener 10 años de experiencia y un título, y tener menos idea aún. Pero eso no quita que, en general, alguien con más experiencia tienda a ser mejor, y alguien con más formación, también.

Al final es muy sencillo. Tan sólo se trata de adquirir las competencias necesarias para desarrollar un trabajo.

Por el hecho de que yo acabase una carrera hace 15 años no creo que tenga más o menos derecho que otro a dedicarme profesionalmente al desarrollo de software. Lo que debería avalarme es mi capacidad para desarrollar software, no cómo la haya adquirido.

No hay posts relacionados.

» Leer más, comentarios, etc...

Blog Bitix

Cómo redirigir peticiones de HTTP a HTTPS en Nginx, Apache, Tomcat, Jetty y WildFly

June 18, 2016 11:00 AM

Usar el protocolo seguro HTTPS proporciona confidencialidad en la comunicación entre el navegador del usuario y el servidor, es una forma de mejorar la seguridad y privacidad. Por ello el buscador de Google lo tiene en cuenta como un parámetro que afecta al SEO siendo mejor usar el protocolo seguro. Sin embargo, el usuario puede estar accediendo por el protocolo no seguro a la página web al poner la dirección en la barra de direcciones o hay enlaces hacia nuestro sitio en otros que hacen uso del protocolo HTTP. Si queremos que nuestro sitio sea accedido únicamente usando el protocolo seguro deberemos hacer una redirección en el servidor.

Nginx
Apache HTTPD

Si tenemos una aplicación o una bitácora que hasta el momento era accedido por el protocolo no cifrado HTTP ahora que Google tiene en cuenta para el SEO que usar el protocolo seguro es un parámetro que tiene en cuenta el algoritmo de posicionamiento en el buscador quizá queramos redirigir todo el tráfico de HTTP al protocolo cifrado HTTPS.

Para usar HTTPS deberemos primero configurar el protocolo TLS/SSL en el servidor web o de aplicaciones usando un certificado SSL que podemos obtener ahora con Let’s Encrypt de forma gratuita o generar un certificado nosotros y que sea firmado por una autoridad de confianza. Una vez que el servidor es capaz de servir el tráfico por el protocolo HTTPS estamos en condiciones de realizar la redirección al protocolo cifrado HTTPS en el puerto 443 cuando sea accedido por el protocolo no cifrado HTTP en el puerto 80.

Dependiendo del servidor web o de aplicaciones que usemos la configuración será distinta, incluso lo podemos hacer a nivel de aplicación con la ayuda del framework web si este ofrece algún soporte para ello. A continuación incluiré la configuración necesaria para los servidores web y de aplicaciones más populares como son Nginx, Apache HTTPD, Tomcat, Jetty y WildFly y finalmente el caso haciendo la redirección a nivel de aplicación con el framework Apache Tapestry para desarrollar aplicaciones web con el lenguaje Java.

Nginx

Usando Docker nos resultará más sencillo hacer la prueba que teniendo que instalar el paquete de Nginx en nuestra distribución. Puedes consultar varios artículos sobre Docker que he escrito a modo introducción y para empezar a usarlo.

En la sección del servidor que escucha en el puerto HTTP (80) realizamos la redirección permanente con el código de estado 301 hacia el protocolo HTTPS. En la sección del servidor que escucha en el pueto HTTPS (443) accitva el uso de TLS/SSL usando varias directivas y sirve los documentos de /usr/share/nginx/html en la ruta /.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/505856d7e0a9574541c303d09fd63be1/raw/nginx.conf">nginx.conf</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/505856d7e0a9574541c303d09fd63be1/raw/docker-nginx.sh">docker-nginx.sh</pre></a></noscript>
Redirección de HTTP a HTTPS en Nginx

Apache HTTPD

La configuración para Apache HTTPD es similar simplemente cambian las directivas según su propia configuración. Se activan los módulos para usar TLS/SSL y el que permite hacer reescrituras de las URL.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/505856d7e0a9574541c303d09fd63be1/raw/httpd.conf">httpd.conf</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/505856d7e0a9574541c303d09fd63be1/raw/docker-httpd.sh">docker-httpd.sh</pre></a></noscript>
Redirección de HTTP a HTTPS en Apache HTTPD

Tomcat, Jetty y WildFly

Es muy habitual que los servidores de aplicaciones como Tomcat, Jetty o WildFly sean accedidos no directamente por el navegador del usuario sino a través de un servidor web como Nginx o Apache haciendo de proxy. Cuando hay un servidor web que actúa de proxy para el servidor de aplicaciones es posible decidir que el establecimiento de la conexión cifrada TLS/SSL del protocolo HTTPS se realice en el servidor web y la comunicación cifrada termine al mismo tiempo en él, la comunicación entre el servidor web y el servidor de aplicaciones se realizaría usando el protocolo HTTP. Esto descarga del servidor de aplicaciones la tarea algo costosa del establecimiento de la conexión cifrada y tener que cifrar el tráfico.

Para el caso de Tomcat, Jetty y WildFly habiendo configurado la posibilidad de usar el protocolo seguro la configuración para hacer la redirección es la misma para los tres, habría que añadir al archivo descriptor web.xml de la aplicación el siguiente fragmento XML. Esto hace que el servidor fuerce la conexión segura para los recursos indicados, en este caso todos al usar el patrón /*.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/505856d7e0a9574541c303d09fd63be1/raw/web.xml">web.xml</pre></a></noscript>

Redirección a nivel de aplicación

Con algún mecanismo propio que empleemos al programar la aplicación (en Java por ejemplo con un filtro) o el framework web que usemos para desarrollar la aplicación web quizá nos ofrezca algún mecanismo para redirigir las peticiones al puerto seguro cuando sea accedida por el puerto inseguro, por ejemplo, para que la redirección la haga la aplicación en vez del servidor con el framework Apache Tapestry basta añadir la siguiente configuración en el módulo de la aplicación.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/505856d7e0a9574541c303d09fd63be1/raw/AppModule.java">AppModule.java</pre></a></noscript>

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./docker-nginx.sh o ./docker-httpd.sh.

» Leer más, comentarios, etc...

Blog Bitix

Atajos de teclado básicos de la terminal en GNU/Linux

June 17, 2016 04:00 PM

Aprender las combinaciones de teclas de aquellas aplicaciones que usamos frecuentemente y durante mucho tiempo nos ayuda a hacer las cosas en menos tiempo y de forma más sencilla. Cada aplicación tiene los suyos propios, en este artículo los de la terminal con el intérprete de comandos bash para GNU/Linux.

Linux
GNU

Si no conoces lo que estás buscando una interfaz gráfica es una buena forma de descubrir cosas, si conoces exactamente lo que buscas y si lo tienes que hacer de forma repetida es tediosa y lenta. La terminal en GNU/Linux sigue siendo una poderosa herramienta para realizar multitud de tareas. Entre sus ventajas son realizar la tareas de forma mucho más directa y simple que con una interfaz gráfica o la posibilidad de automatizar tareas repetitivas en un script bash o en un lenguaje de programación como Python. Entre las desventajas de la línea de comandos está que no suele ser tan intuitiva como una interfaz gráfica. Dadas las ventajas de la terminal o línea de comandos para algunas personas su uso es muy frecuente y en GNU/Linux es común tener que usarla en algún momento, conocer las combinaciones de teclas que podemos usar la tarea será más fácil y la haremos rápidamente.

En el intérprete de la terminal bash podemos usar las siguientes combinaciones de teclas:

  • Ctrl+a: lleva el cursor al inicio de la línea de comandos.
  • Ctrl+e: lleva el cursor al final de la línea de comandos.
  • Ctrl+l: limpia la terminal, similar a lo que hace el comando clear.
  • Ctrl+u: limpia desde la posición del cursor hasta el inicio de la línea. Si se está al final limpia la línea entera.
  • Ctrl+k: limpia desde la posición del cursor hasta el final de la línea. Si se está al inicio limpia la línea entera.
  • Ctrl+h: hace lo mismo que la tecla backspace, borra el caracter inmediatamente anterior a la posición del cursor.
  • Ctrl+w: borra la palabra inmediatamente antes del cursor.
  • Alt+d o Esc+d: borra la palabra siguiente después del cursor.
  • Ctrl+p: establece la línea de comandos con el último comando introducido.
  • Ctrl+r: inicia la búsqueda de comandos usados anteriormente, tecleando parte de un comando usos anteriores que hayamos realizado incluyendo las opciones y parámetros. Hecha una búsqueda pulsando de nuevo la combinación de teclas encontraremos coincidencias anteriores.
  • Ctrl+c: termina el proceso que se esté ejecutando, útil para recuperar el control del sistema.
  • Ctrl+d: sale de la terminal, similar al comando exit.
  • Ctrl+z: suspende la ejecución del proceso que se está ejecutando y lo pone en segundo plano, con el comando fg podremos volver a continuar su ejecución.
  • Ctrl+t: intercambia la posición de los dos caracteres antes del cursor, útil para corregir malos tecleos.
  • Esc+t: intercambia la posición de las dos palabras antes del cursor, útil para corregir malos tecleos.
  • Alt+f: mueve el cursor al inicio de la palabra siguiente de la línea, lo mismo que Ctrl+right en la terminal de GNOME.
  • Alt+b: mueve el cursor al inicio de la palabra anterior de la línea, lo mismo que Ctrl+left en la terminal de GNOME.
  • Tab: autocompleta comandos o rutas de directorios o archivos.

Poner comandos en segundo plano es útil si un proceso deja el sistema sin respuesta o queremos introducir otro antes de que termine el primero. Con tres comandos podemos manejar los procesos en primer y segundo plano:

  • jobs: con este comando podremos ver la lista de procesos en segundo plano, con información de si están detenidos/suspendidos o en ejecución además del identificativo asignado para usar en los comandos fg y bg.
  • fg: pone en primer plano un proceso, si estaba suspendido reanuda su ejecución.
  • bg: continua la ejecución del proceso pero lo deja en segundo plano, si emite contenido a la terminal se mostrará y quizá nos moleste al seguir trabajando.
  • kill: con el identificativo del proceso en segundo plano y un símbolo de porcentaje por delante podemos enviar la señal de terminado del proceso. Ejemplo, kill %1.
  • Añadiendo un ampersand, &, al final del comando pondremos el comando en ejecución pero en segundo plano directamente.

Las anteriores combinaciones de teclas son del intérprete de comandos bash, el emulador de terminal que usemos también incorpora algunas combinaciones de teclas más. En el caso del emulador del terminal de GNOME podemos usar las siguientes combinaciones muy útiles:

  • Ctrl+Shift+f: abre un diálogo para hacer una búsqueda de texto en la salida de la terminal.
  • Ctrl+Shift+g: busca la siguiente ocurrencia de la búsqueda previa en la terminal.
  • Ctrl+Shift+h: busca la anterior ocurrencia de la búsqueda previa en la terminal.
  • Ctrl+Shift+c: copia el texto seleccionado de la terminal al portapapeles.
  • Ctrl+Shift+v: pega el texto del portapapeles en la línea de comandos.
  • Up: establece en la línea de comandos el comando anterior del historial, igual que Ctrl+p.
  • Down: establece en la línea de comandos el siguiente comando del historial.
  • Left Mouse: selecciona líneas de texto de la terminal.
  • Ctrl+Left Mouse: selecciona bloques de texto de la terminal.
Terminal de GNOME con el intérprete de comandos bash

» Leer más, comentarios, etc...

Picando Código

Que la información sea un derecho y no un delito

June 17, 2016 03:00 PM

Copio y pego información de un evento promocionado por Creative Commons Uruguay sobre vigilancia comercial y estatal, el acceso a la información y la reforma de la ley de derechos de autor. Ahí estaremos:

Que la información sea un derecho y no un delito

El próximo miércoles 22 de junio nos vamos a juntar para discutir sobre el lugar de la información en la nueva agenda de derechos. En el marco de la semana de acción global de solidaridad por la situación de privación de libertad de Julian Assange, desde Proderechos y Creative Commons Uruguay invitamos a todas y todos a discutir sobre la vigilancia comercial y estatal, el acceso a la información y la reforma de la ley de derechos de autor. La actividad va a tener lugar el miércoles 22 de junio a las 19 hs en Casa Tomada (Soriano 762 esquina Ciudadela, Montevideo).

¿Qué porción de nuestra privacidad estamos dispuestos a ceder frente a los nuevos medios de vigilancia pública y privada? ¿Pueden los estados limitar nuestro derecho a la privacidad para brindarnos mayor seguridad? ¿Cómo se regula en Internet la libertad de expresión y la protección de la intimidad? ¿Hasta dónde llega el derecho de acceso a la información de los ciudadanos, frente a estados y corporaciones? ¿Puede considerarse el conocimiento una propiedad privada? ¿Las acciones cotidianas de acceso al conocimiento e información -como sacar fotocopias, o descargar información de internet- deben seguir siendo delitos?

Como panelistas estarán: Gabriel Delacoste (politólogo), Mariana Fossatti (socióloga, integrante de Creative Commons Uruguay), Sebastián Sabini (diputado) y Fabrizio Scrollini (abogado, integrante de DATA Uruguay). Moderará Victoria Carranza, integrante de Proderechos. Se proyectarán grabaciones de las intervenciones de Julian Assange y otros destacados activistas internacionales.

Visitá también el evento en Facebook.

» Leer más, comentarios, etc...

Poesía Binaria

Descubrimos WP-CLI para hacer maravillas y automatizar tu WordPress al máximo

June 17, 2016 08:30 AM

photo-1443916568596-df5a58c445e9
WordPress es el CMS más popular hasta el momento. Solo que orientado al mundo blog o blogosfera, a día de hoy se hacen webs de diversa índole aprovechando sus capacidades de extensión. Aunque a los que llevamos mucho tiempo en la informática, las siglas WP nos recuerdan a WordPerfect1, pero no tiene nada que ver.
Como sabrán muchos lectores de este blog, normalmente prefiero las soluciones de línea de comandos para muchas tareas frente a otras soluciones gráficas más bonitas e intuitivas, ya que éstas últimas suelen ser más lentas, requieren un proceso constante de interacción por mi parte y es muy difícil automatizarlas.

Ahora viene lo bueno, ¿hay alguna forma de utilizar WordPress desde una interfaz de línea de comandos?
¡Por supuesto! Desde finales de 2011 tenemos con nosotros un desarrollo inicialmente hecho por Andreas Creten2 y Cristi Burcä3, aunque ahora su principal mantenedor es Daniel Bachhuber4 (encontramos sus enlaces de GitHub abajo del todo) llamado WP-CLI5.

¿Qué hace WP-CLI?

Básicamente es una interfaz en línea de comandos que nos permite utilizar WordPress sin necesidad de ver una web (aunque sí que necesitaremos acceso SSH al servidor donde tenemos alojado el blog).
Entre otras cosas, nos permite realizar instalaciones de WordPress, instalar plugins, temas, actualizarlos, gestionar comentarios, taxonomías, widgets, posts, páginas, usuarios, base de datos y muchas cosas más, todo desde nuestra línea de comandos. Y, por supuesto, podemos automatizar todas las acciones, lo cual nos permite ahorrar muchísimo tiempo en tareas repetitivas o al menos, si alguna operación va a tardar un rato, no necesitamos estar delante cargando decenas de apartados en el navegador y realizando tareas que requieren nuestra presencia y atención (y, si gestionas muchos blogs te puede venir muy bien).

Requerimientos

Para poder utilizar WP-CLI necesitamos:

  • Acceso SSH a un servidor (para trabajar en remoto), aunque también podemos trabajar en local si queremos. Puede ser Linux, OSX, o cualquier *nix o incluso Windows, aunque en Windows podremos hacer menos cosas.
  • PHP 5.3 o superior (recomiendan 5.3.29, pero funciona con la 5.3.19 sin embargo, a día de hoy, como mínimo una 5.5 la tenemos todos).
  • cURL instalado y su módulo para PHP también.
  • WordPress 3.7 o superior (aunque podremos instalarlo desde WP-CLI, pero no gestionar instancias más antiguas.

Instalación

WP-CLI no es un plugin de WordPress, por lo que no tenemos que instalarlo con el entorno de administración de éste. Es más, WP-CLI es capaz de automatizar tus instalaciones de WordPress. ¿Necesitas hacer varias instalaciones de WP en un servidor? Con esta herramienta puedes hacerlo en cuestión de segundos. WP-CLI será lo primero que instales.

Debemos hacerlo de la siguiente forma:

$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
$ sudo mv wp-cli.phar /usr/local/bin/wp
$ sudo chmod +x /usr/local/bin/wp

Con esto, lo tendremos instalado a nivel de sistema. Por lo que, en cualquier lado, podemos ejecutar:

$ wp –info
PHP binary: /usr/local/php54/bin/php-cli
PHP version: 5.4.45
php.ini used: /usr/local/php54/lib/php.ini
WP-CLI root dir: phar://wp-cli.phar
WP-CLI packages dir: /home/poesiab8/.wp-cli/packages/
WP-CLI global config:
WP-CLI project config:
WP-CLI version: 0.23.0

y nos dará información básica sobre el programa. Además, si a menudo trabajas con la línea de comandos, seguro que la tecla Tab la tienes desgastada, porque conseguimos que escriba lo que nos da pereza escribir, además de ayudarnos a recordar mucha información. Esto se llama bash completion, y muchísimos vienen acompañados de un pequeño script que nos ayuda con esto. WP-CLI no va a ser menos. Podemos descargarlo e instalarlo:

wget https://github.com/wp-cli/wp-cli/raw/master/utils/wp-completion.bash
sudo mkdir -p /usr/local/share/bash-completion/completions
sudo mv wp-completion.bash /usr/local/share/bash-completion/completions

Ahora en nuestro $HOME, añadir al archivo .bashrc las siguientes líneas al final:

1
2
3
4
if [ -f "/usr/local/share/bash-completion/completions/wp-completion.bash" ];
then
   source /usr/local/share/bash-completion/completions/wp-completion.bash;
fi

Así, nada más entrando en el sistema podremos disfrutar de esta ayuda. Si no queremos salir y volver a entrar, podemos hacer:

$ source /usr/local/share/bash-completion/completions/wp-completion.bash

Recapitulando

También podemos crear un pequeño script que lo haga todo por nosotros, muy útil si tenemos que hacer varias instalaciones de WP-CLI (el script necesita sudo, y preguntará la contraseña, pero no es difícil de adaptar):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#/bin/bash

OLDPWD="$(pwd)"
cd /tmp/

# Descarga e instala WP-CLI
wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
sudo chmod +x /usr/local/bin/wp

# Descarga e instala WP-CLI completion
wget https://github.com/wp-cli/wp-cli/raw/master/utils/wp-completion.bash
sudo mkdir -p /usr/local/share/bash-completion/completions
sudo mv wp-completion.bash /usr/local/share/bash-completion/completions

# Instala WP-CLI completion en el usuario actual
cp $HOME/.bashrc $HOME/.bashrc_old
echo "if [ -f \"/usr/local/share/bash-completion/completions/wp-completion.bash\" ]
then
    source /usr/local/share/bash-completion/completions/wp-completion.bash;
fi"
>> $HOME/.bashrc
source /usr/local/share/bash-completion/completions/wp-completion.bash

cd "$OLDPW"

También podemos instalarlo en Windows, o utilizar Composer o Brew, tenemos mucha más información en la web oficial.6.

Actualización

WP-CLI soporta auto-actualización (como composer), es decir, ejecutando:

$ wp cli update

Automáticamente se descargará la última versión y se sobreescribirá el archivo actual (debemos tener permisos para ello, por ejemplo si está instalado con privilegios de root, debemos ser root, o hacer sudo si está disponible).

Antes de empezar

WP-CLI puede administrar múltiples instancias de WordPress en un mismo servidor, tanto si tienes una instalación para cada blog WordPress como si dispones de configuración multisitio7.
Es recomendable, antes de utilizar WP-CLI acceder al directorio del servidor donde tenemos la instalación de WordPress (a no ser que lo estemos instalando), de la siguiente forma:

$ cd www/mi_blog/www/
$ wp core version

Aunque, también podemos hacer lo siguiente (aunque puede ser algo incómodo):

$ wp core version –path=www/mi_blog/www

Tareas básicas

Ahora viene lo interesante, todo lo que podemos hacer con WP-CLI, al menos algunas tareas comunes como las siguientes:

Instalación de WordPress

Para hacer la instalación, debemos dar varios pasos previos:

  • Descarga de archivos: seguro que alguna vez te has descargado WordPress, lo has descomprimido en tu ordenador y lo has subido al servidor por FTP. Al tratarse de muchos archivos, este método es lento, necesita mucha interacción humana, además, la conexión a Internet de un ordenador personal suele ser mucho más lenta que la de un servidor. Por otro lado, el servidor puede hacer muchas cosas, si has usado SSH antes, sabrás lo que quiero decir. WP-CLI nos permite descargar y descomprimir WordPress con sólo un comando.

    $ wp download –path=directorio_local –locale=idioma

  • Configuración de WordPress: el primer paso, tras la instalación es decir el host, nombre de usuario, clave y demás información relativa a la base de datos. Pero esto lo podemos automatizar, quitar el mensaje de bienvenida y ahorrar un precioso tiempo:

    $ wp core config –dbname=”BASEDEDATOS” –dbuser=”USUARIODB” –dbpass=”PASSDB” –dbhost=”HOSTDB” –dbprefix=”PREFIJODB” –locale=”idioma”

  • Instalación de WordPress: tras enviar la información de base de datos, nos pedirá información sobre el blog; darle un nombre, un usuario administrador y una contraseña. Esto lo podemos hacer con:

    $ wp core install –url=”DIRECCION” –title=”TITULO DEL BLOG” –admin_user=”USUARIO_ADMINISTRADOR” –admin_password=”PASSWORD” –admin_email=”MAIL ADMINISTRADOR”

  • Un ejemplo real

    Queremos instalar un WordPress en español en www.midominio.com/blog; la base de datos estará en localhost (en el mismo servidor web), el usuario será dbuser, la clave dbpassword, la base de datos, blogs y el prefijo “wp_”. El usuario administrador de WordPress será blogadmin y la clave “passwordcomplicado”. El título del blog será “Un blog sobre WP-CLI”. Podremos hacerlo ejecutando tres comandos:

    $ wp download –path=www/blog –locale=”es_ES”
    $ cd www/blog
    $ wp core config –dbname=”blogs” –dbuser=”dbuser” –dbpass=”dbpassword” –dbhost=”localhost” –dbprefix=”wp_” –locale=”es_ES”
    $ wp core install –url=”http://midominio.com/blog” –title=”Un blog sobre WP-CLI” –admin_user=”blogadmin” –admin_password=”passwordcomplicado” –admin_email=”info@midominio.com”

    O si queremos algo más general… incluso para que nos dé un password generado, tal y como hace un WordPress moderno:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    DB_HOST="localhost"
    DB_USER="dbuser"
    DB_PASSWORD="dbpassword"
    DB_NAME="blogs"
    DB_PREFIX="wp_"

    WP_TITLE="Un blog sobre WP-CLI"
    WP_LOCALE="es_ES"
    WP_URL="http://midominio.com/blog"

    ADMIN_PASSWORD=$(pwgen -sy 12 1)
    ADMIN_USER="blogadmin"
    ADMIN_MAIL="info@midominio.com"

    wp download --path=www/blog --locale="$WP_LOCALE"
    cd www/blog
    wp core config --dbname="$DB_NAME" --dbuser="$DB_USER" --dbpass="$DB_PASSWORD" --dbhost="$DB_HOST" --dbprefix="$DB_PREFIX" --locale="$WP_LOCALE"
    wp core install --url="$WP_URL" --title="$WP_TITLE" --admin_user="$ADMIN_USER" --admin_password="$ADMIN_PASSWORD" --admin_email="$ADMIN_MAIL"
    echo "El password es: "$ADMIN_PASSWORD

    Esto nos puede permitir automatizar al máximo la creación de blogs. Por ejemplo si tenemos varias webs alojadas en el mismo servicio de hospedaje, o un VPS. Esto nos puede hacer ahorrar muchísimo tiempo.
    ¿Parece poco ahorro? Bueno, como veremos más adelante, podremos instalar plugins desde aquí, podemos crear un pequeño script que automatice la instalación de WordPress, plugins y algo de configuración básica.

    Copia de seguridad

    Podemos importar y exportar la base de datos de forma muy rápida con las siguientes órdenes:

    $ wp db export backup.sql

    Y luego

    $ wp db import backup.sql

    Lo que nos puede ayudar bastante para las copias de seguridad. No está de más hacer una copia de los archivos, si el directorio de WordPress está en /home/usuario/www/blog/ podemos ir a /home/usuario y hacer lo siguiente:

    $ tar cvjpf blog_backup.tar.bz2 www/blog

    para realizar la copia y,

    $ tar xvjpf blog_backup.tar.bz2

    para restaurarla.

    De todas formas, existen plugins que pueden interactuar con WP-CLI para realizar una copia completa de seguridad8

    Actualizar versión

    Si hacemos:

    $ wp core version
    4.5.0

    Nos mostrará la versión que tenemos instalada actualmente (El post está publicado el 17 de junio de 2016). Nota: no me gusta hacer actualizaciones del core o de plugins/temas/etc sin haber hecho un backup completo primero. En el pasado, hacerlo así me ha salvado la vida varias veces.

    A partir de aquí podemos hacer una actualización:

    $ wp core update

    Automáticamente se actualizará y se instalará la actualización. No está de más hacer justo después:

    $ wp core update-db

    Ahora probamos nuestro blog, y navegamos un poco para ver que todo está bien.

    Ejecutar SQL directamente

    Esto me encanta. Normalmente puedo acceder a la base de datos ejecutando el comando mysql, con usuario y password de un usuario con privilegios (al tener varios blogs, tengo varios usuarios de base de datos con passwords generados, no me los sé todos y me da mucha pereza mirarlos).
    De esta forma, al ejecutar WP-CLI sobre un blog determinado, se ejecutará la consulta sólo sobre el usuario de dicho blog, por lo que la seguridad no será ya un problema.
    Podemos hacer:

    $ wp db query “SHOW TABLES;”

    o si tenemos la consulta SQL en un archivo:

    $ wp db query < consultas.sql

    ¿Quieres saber qué puedes hacer desde aquí? Visita este post para coger ideas.

    Configurar (de todo)

    Una de las tareas más arduas cuando instalas WordPress es configurarlo, recorrer todas las opciones y pasar por varias pantallas hasta finalizar todos los parámetros de configuración disponibles. Algunos los definimos, otros los revisamos, pero entre opciones del tema, plugins, generales, etc serán varias pantallas y si tenemos que configurar varios blogs, podemos perder muchísimo tiempo en estas tareas.

    Para ello tenemos:

    wp option

    Que nos permitirá consultar y definir valores de configuración de WordPress. Para empezar, podemos listar los elementos que nos deja configurar:

    $ wp option list

    Con esto veremos un listado de todas las opciones presentes, algo parecido a esto:
    Screenshot 14-06-2016-230644

    También tenemos las órdenes:

    $ wp option get [opcion]

    Pero claro, en este gestor de contenidos, si hemos revisado alguna vez las opciones del plugin (o hemos hecho un traslado de dominio a través de una copia de seguridad de la base de datos) veremos que muchas configuraciones vienen serializadas, es decir, tienen la siguiente forma:

    |widget_categories|
    a:2:{i:2;a:4:{s:5:”title”;s:0:””;s:5:”count”;i:0;s:12:”hierarchical”;i:0;s:8:”dropdown”;i:0;}s:12:”_multiwidget”;i:1;}

    Personalmente no me gusta, pero en WordPress no tenemos muchas más formas de categorizar una configuración y, desde el punto de vista de PHP es muy fácil y rápido serializar un array para escribir dicha configuración en base de datos. Aunque wp option get nos permite visualizar la variable de configuración con naturalidad, así:

    array (
    2 =>
    array (
    ‘title’ => ”,
    ‘count’ => 0,
    ‘hierarchical’ => 0,
    ‘dropdown’ => 0,
    ),
    ‘_multiwidget’ => 1,
    )

    De igual forma, podemos definir valores a las opciones de WordPress, como siempre, con vistas a configurar blogs de forma automática, utilizando:

    $ wp option set [opción] [valor]

    Tal y como sucedía con el ejemplo anterior, los nombres de las opciones, los podemos conseguir cuando obtenemos la lista, una de las cosas que podemos definir es:

    $ wp option set rss_use_excerpt 1

    El problema, como antes, surge cuando queremos cambiar uno de los valores que vienen en un array serializado, lo cual podríamos hacerlo de varias formas, entre ellas:

    • Podemos obtener el dato serializado en json:

      $ wp option get widget_categories –format=json

      luego editar el dato dentro del json resultante, por ejemplo el título, y volver a cargar en JSON las opciones:

      $ wp option set widget_categories –format=json ‘{“2″:{“title”:”Categor”,”Counts”:0,”hierarchical”:0,”dropdown”:0},”_multiwidget”:1}’

      aunque de esta forma necesitaríamos algo de interacción, o crear una expresión regular.

    • No obstante podemos utilizar PHP para convertir el JSON en un array, editar el contenido desde el array y volverlo a pasar a JSON:

      wp option set widget_categories “$(echo “{2}->title=’Categorias'; echo json_encode(\$original);” | php -n)”

      Estamos haciéndolo todo del tirón desde un script de bash. Veámoslo detenidamente:

      • wp option set widget_categories “VALOR” : definirá el valor en las opciones de WordPress. Aunque para definir el valor, vamos a utilizar una secuencia de comandos.
      • $(echo “<?php ÓRDENES PHP;” | php)” : Interpretará las órdenes en PHP y las pasará como argumento (al comando anterior)
      • $(wp option get widget_categories –format=json) : Obtendrá el valor en JSON de la opción widget_categories y lo pasará como argumento (que lo hemos metido dentro del PHP que estamos interpretando).
      • Como las variables PHP y las variables de BASH empiezan por $ para definir una variable en PHP tenemos que escapar el símbolo de $ poniendo una \ delante.

    Información sobre los posts

    Podemos, también obtener información sobre los posts publicados, como listarlos:

    $ wp post list

    donde obtendremos IDs, títulos, slugs, fechas y estados (si está publicado, borrador, programado…), aunque si leemos la documentación veremos opciones para filtrar la búsqueda por diferentes criterios; o bien, obtener información completa de un post concreto como:

    $ wp post get 1

    donde 1, en este caso es el ID del post que queremos visualizar, devolviéndonos algo como esto:

    +-----------------------+-----------------------------------------------------+
    | Field                 | Value                                               |
    +-----------------------+-----------------------------------------------------+
    | ID                    | 1                                                   |
    | post_author           | 1                                                   |
    | post_date             | 2016-06-12 13:37:08                                 |
    | post_date_gmt         | 2016-06-12 13:37:08                                 |
    | post_content          | Bienvenido a WordPress. Esta es tu primera entrada. |
    |                       |  Edítala o bórrala, ¡y comienza a escribir!         |
    | post_title            | ¡Hola mundo!                                        |
    | post_excerpt          |                                                     |
    | post_status           | publish                                             |
    | comment_status        | open                                                |
    | ping_status           | open                                                |
    | post_password         |                                                     |
    | post_name             | hola-mundo                                          |
    | to_ping               |                                                     |
    | pinged                |                                                     |
    | post_modified         | 2016-06-12 13:37:08                                 |
    | post_modified_gmt     | 2016-06-12 13:37:08                                 |
    | post_content_filtered |                                                     |
    | post_parent           | 0                                                   |
    | guid                  | http://mi-blog.com/?p=1                             |
    | menu_order            | 0                                                   |
    | post_type             | post                                                |
    | post_mime_type        |                                                     |
    | comment_count         | 1                                                   |
    +-----------------------+-----------------------------------------------------+
    

    Esto puede ser útil, incluso si ponemos –format=json en la llamada anterior para obtener toda la información del post y pasarla a otro programa o a un script y aplicarle un tratamiento, podríamos hacer búsquedas por contenido.

    Borrar posts automáticamente

    Igual que podemos crear, podemos destruir. Puede que alguna vez hayamos creado un post con fecha de caducidad, cuya información no es válida o no tiene sentido pasada una fecha, por ejemplo, si hacemos una campaña de publicidad de un producto o servicio. Podemos hacer que cuando llegue la fecha límite, dicha publicidad desaparezca:

    $ wp post delete ID

    que manda el post a la papelera la primera vez que se ejecuta (la segunda vez borra definitivamente el post) o,

    $ wp post delete ID –force

    que lo borra directamente.

    Aunque, si hemos generado varios posts de prueba, podemos eliminarlos todos de la siguiente manera:

    $ wp post delete {1..100}

    que borraría todos los posts con IDs comprendidas entre 1 y 100.

    Un escritor automático

    Para terminar con el listado de opciones de WP-CLI en este post (porque este programa da muchísimo más de sí), vamos a hablar de la escritura de posts de forma automática. En primer lugar, podemos generar una serie de posts idénticos, lo que nos puede servir para hacer pruebas con temas o plugins de la siguiente forma:

    $ curl http://loripsum.net/api/5 | wp post generate –post_content –count=10

    Así, primero nos bajamos un texto de lorem ipsum y luego lo pasamos al generador de posts, que creará 10 posts con ese contenido. Podríamos crear también páginas si añadimos (–post_type=page) o modificar la fecha con (–post-date “yyyy-mm-dd”).

    Aunque lo que de verdad se lleva la palma es la capacidad de enviar posts. Es decir, podríamos hacer un programa o script que creara un post o página automáticamente con contenidos de diferentes fuentes en diversas condiciones. Podemos poner como ejemplo un post que se envíe automáticamente cuando da lluvia a través de una web meteorológica o si queremos dejar volar nuestra imaginación, cuando nuestro proyecto con Arduino detecta lluvias; o incluso un post que se despida del mundo cuando estemos muertos si, por ejemplo, llevamos mucho tiempo sin entrar en el servidor o hacer una tarea rutinaria, sólo por poner algunos ejemplos.
    A la hora de enviar el post debemos hacer lo siguiente:

    $ wp post create [fichero_de_contenidos] –post-type=post –post-title=”Título de mi post” –post-category=12,32,54

    De esta forma leeremos un fichero de texto con el contenido del post (que también podemos generarlo con un script o descargarlo…), en el tipo podríamos especificar post o página, el título lo podemos personalizar también así como la categoría (que tiene que ir por número).

    También podemos programar un post si especificamos –post-status=future –post-date=”yyyy-mm-dd HH:MM:SS”.

    Y mucho más…

    Podría rellenar varios posts con las capacidades de WP-CLI, pero debemos dejar algo a la imaginación y la investigación. ¿Qué más cosas podemos hacer?

    • Administrar usuarios
    • Administrar los permisos de los diferentes roles de usuarios (wp cap)
    • Administrar cachés (wp cache)
    • Administrar tareas programadas o cron jobs (wp cron)
    • Administrar menús
    • Administrar plugins del propio WP-CLI que nos permitirán funciones personalizadas (wp package)
    • Muchísimo más

    WP-CLI en Siteground

    Siteground España es un proveedor especializado en servicios de hosting WordPress profesionales con servidores robustos y que facilita enormemente la labor de administrar un blog con WordPress manteniendo constantemente todos los sistemas al día.

    Y, por supuesto, no podían dejar a los amantes de la consola de lado, proporcionando un acceso por SSH a los servidores, y por supuesto, disponemos de una instalación de WP-CLI siempre actualizada.

    Para conectar por SSH a nuestro sitio de SiteGround, primero, debemos acceder a cPanel y buscar en las opciones Acceso SSH Shell
    Screenshot 16-06-2016-000641
    Luego, en la siguiente pantalla, debemos configurar nuestra clave RSA, para ello, aunque SiteGround nos permite generar un par de claves desde el entorno web y descargarnos nuestra clave privada (que luego tendremos que copiar en nuestro equipo), yo prefiero ejecutar lo siguiente en mi terminal:

    $ ssh-keygen -b 4096

    Luego puedo guardar mi clave en mi ordenador, y subir la clave pública (copiar y pegar) donde pone Upload SSH key:
    Screenshot 16-06-2016-000649

    Luego, una vez hecho esto, basta con acceder al SSH de nuestro servidor en SiteGround desde un terminal:

    $ ssh -p 18765 [usuario]@[dominio.com]

    Donde el usuario es el mismo que utilizas para entrar en el panel de control de SiteGround y el dominio es tu dominio principal del hosting.

    Ahora, sólo puedo decir una cosa… ¡ a disfrutar !

    Referencias

    Al ser un post patrocinado, y como hice otras veces, los enlaces externos que incluyo a lo largo del post, los resumo aquí, y que los enlaces de la marca sean los primeros.

  1. Wordperfect
  2. Andreas Creten
  3. Cristi Burcă
  4. Daniel Bachhuber
  5. WP-CLI oficial
  6. Installing WP-CLI
  7. Cómo activar MultiSitio en WordPress
  8. Backup WordPress Plugin
  9. 21 Consultas SQL para administrar fácilmente nuestro WordPress

Foto: Austin Schmid

The post Descubrimos WP-CLI para hacer maravillas y automatizar tu WordPress al máximo appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Poesía Binaria

Generando la salida de nuestros programas con plantillas en C++ con Silicon en pocas líneas

June 13, 2016 08:21 AM

photo-1456983887044-b5ecb1059660

A medida que el hardware y el software van evolucionando, van cambiando las preferencias a la hora de desarrollar un producto. Hace unos años, el objetivo principal era que el producto final funcionara, intentar hacer el mínimo número de operaciones para que el software corriera en un ordenador de la mejor forma posible. Desde hace unos años, el hardware es capaz de hacer muchas cosas y muy rápido, los lenguajes han evolucionado y se han optimizado mucho; por lo tanto, podemos aprovechar y hacer que desde el punto de vista del mantenimiento, legibilidad del código, hacer que el código sea poesía y hacer que todas las piezas encajen perfectamente.
Es decir, ya no se suelen ver sentencias goto en ningún código (quien busca encuentra, pero a no ser que el desarrollador sepa lo que hace y sin ellas se vea muy mermado el rendimiento se intentan evitar). Pero aún así, es común que en diferentes programas encontremos uso de programación orientada a objetos, modelo-vista-controlador, identificadores en cadena de texto en lugar de numéricos (o enums) en medio del código para hacernos fácil el mantenimiento o representación y el hecho de compartir el código con otros, crear clases lo más generales posible y luego particularizarlas con nuestras necesidades, incluso, interpretar muchas partes a través de scripts (es decir, utilizar un lenguaje ya existente o inventarnos el nuestro para programar ciertas partes, o dejar que el usuario pueda programarlas).

En este caso, vengo a tratar el tema de las plantillas, o lo que es lo mismo: queremos generar una salida con un formato determinado, imaginémonos un texto:

Hey Jugador1, has conseguido 123 puntos y has perdido

Imaginemos que estamos haciendo un juego y queremos generar ese mensaje (empezamos por algo sencillo), pero a partir de aquí podemos obtener varias combinaciones de mensajes que podemos resumir sustituyendo parte del texto por palabras móviles, es decir, cosas que en el futuro cambiaremos por lo que más nos convenga:

Hey %nombreJugador%, has conseguido %puntos% puntos y has %destino%

Así el jugador se puede llamar como queramos, puede tener el nombre que quiera, conseguir los puntos que quiera y lo que ha pasado con el, puede haber ganado o haber perdido.
Esto me recuerda horrores a un simple printf (o sprintf) en el que la cadena es: “Hey %s, has conseguido %d puntos y has %destino%”. Pero claro, puede que en otros idiomas, o porque luego veamos que quede mejor, el mensaje ahora sea. Has sacado %puntos% puntos. %nombreJugador% has %perdido%. Aquí el caso del printf ya no nos sirve, porque importa el orden de los elementos.

Reemplazar texto

Lo primero que podemos probar para nuestro sistema de plantillas, podemos verlo aquí. Es decir, un sistema que nos permita reemplazar cadenas por otras cadenas. De esta forma cuando encontremos:

  • %nombreJugador% : lo cambiaremos por el nombre del jugador
  • %puntos% : lo cambiaremos por los puntos conseguidos.
  • %destino% : lo cambiaremos por un “ganado” o “perdido”

Ahora no nos importa que nos cambien el orden de las palabras clave, porque da igual dónde encontremos una, ésta se sustituirá por su equivalencia. Podemos ver un ejemplo aquí (C++11):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <string>
#include <map>

using namespace std;

string replace2(string source, std::map<string,string>strMap, int offset=0, int times=0)
{
  int total = 0;
  string::size_type pos=offset;
  string::size_type newPos;
  string::size_type lowerPos;

  do
    {
      string rep;
      for (std::map<string, string>::iterator i=strMap.begin(); i!=strMap.end(); ++i)
    {
      string fromStr = i->first;

      newPos = source.find(fromStr, pos);
      if ( (i==strMap.begin()) || (newPos<lowerPos) )
        {
          rep = fromStr;
          lowerPos = newPos;
        }
    }

      pos = lowerPos;
      if (pos == string::npos)
    break;

      string toStr = strMap[rep];

      source.replace(pos, rep.length(), toStr);
      pos+=toStr.size();

    } while ( (times==0) || (++total<times) );

  return source;
}

int main()
{
  int puntuacion = 100;
  int enemigo = 90;

  string original = "Hey %nombreJugador% has ganado %puntos% puntos y has %destino%";
  map<string,string> mapa = { { "%nombreJugador%", "Gaspar" }, {"%puntos%", to_string(puntuacion)}, {"%destino%", (puntuacion>enemigo)?"ganado":"perdido"}};

  cout << "Original string: "<<original<<endl;

  cout << "Resulting string: "<<replace2(original, mapa)<<endl;

  return 0;
}

Condicional en la plantilla

Por ahora nos vale, aunque poco a poco veremos la necesidad de hacer la lógica un poco más compleja. ¿Y si no nos limitamos a sustituir palabras, sino que introducimos algo de lógica en el sistema de plantillas? Esto nos permitiría entre otras cosas aislar por completo el idioma de nuestro código, eliminando las palabras ganado y perdido. En este caso, a la plantilla le damos todas las palabras, y ya el sistema de plantillas se encargará de devolvernos la cadena definitiva. Para este ejemplo usaré la biblioteca Silicon (la de arriba):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <string>
#include "silicon.h"

using namespace std;

int main()
{
  int puntuacion = 100;
  int enemigo = 90;

  string original = "Hey {{nombreJugador}} has ganado {{puntos}} puntos y has {%if puntos>enemigodestino}}ganado{/if}}{%if puntos<enemigodestino}}perdido{/if}}";
  Silicon t = Silicon::createFromStr(original);
  try
    {
      t.setKeyword("nombreJugador", "Gaspar");
      t.setKeyword("puntos", std::to_string(puntuacion));
      t.setKeyword("enemigo", std::to_string(enemigo));

      cout << t.render()<<std::endl;
    }
  catch (SiliconException &e)
    {
      cout << "Exception!!! "<<e.what() << std::endl;
    }
}

Ahora vemos que la plantilla ha cambiado un poco. Vemos por ejemplo que las palabras clave, ahora vienen entre dobles paréntesis y, además, encontramos una simple lógica en su representación. El propio sistema de plantillas evalúa la expresión y decide qué palabra mostrar (está en sus primeras versiones, por ahora no tiene else…), pero al menos, cuando le pasamos las palabras clave al sistema, no hay que poner los caracteres comodín (% antes, {{, }} ahora). Además, este sistema nos permite incluso modificar la lógica sin necesidad de compilar (en el caso en que las plantillas se encuentren en un fichero, o incluso las puedas descargar de Internet en tiempo real).

Llamar a funciones para obtener datos pesados

Otra cosa curiosa es que podemos configurar ciertos textos como funciones. Es decir, como estamos dando flexibilidad a la hora de crear plantillas. Podemos también definir muchos keywords, algunos pueden salir siempre, otros algunas veces. Y puede que otros, para obtener el dato se demoren un poco: pensemos en que tenga que ser un valor calculado o descargar de la red un cierto dato antes de representarlo. Para hacer la simulación, vamos a hacer que el dato de obtención del record mundial se retrase un par de segundos. En este caso, veremos dos plantillas, una con el récord y otra sin él, y sólo debe retrasarse la que muestra el récord.

Por ejemplo, podemos ver el siguiente código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <string>
#include "silicon.h"
#include <thread>
#include <chrono>

using namespace std;

std::string worldRecord(Silicon* s, std::map<std::string, std::string> args, std::string input)
{
  std::this_thread::sleep_for(std::chrono::seconds(2));
  return "42";
}

int main()
{
  int puntuacion = 100;
  int enemigo = 110;

  string original = "Hey {{nombreJugador}} has ganado {{puntos}} puntos y has {%if puntos>enemigo}}ganado{/if}}{%if puntos<enemigo}}perdido{/if}}";
    //    "{!block template=bloque.html/}\n"
  Silicon t = Silicon::createFromStr(original);
  try
    {
      t.setKeyword("nombreJugador", "Gaspar");
      t.setKeyword("puntos", std::to_string(puntuacion));
      t.setKeyword("enemigo", std::to_string(enemigo));
      t.setFunction("worldRecord", worldRecord);

      cout << t.render()<<std::endl;
      t.setData(original+"\nEl récord mundial es de {!worldRecord/}");
      cout << t.render()<<std::endl;
    }
  catch (SiliconException &e)
    {
      cout << "Exception!!! "<<e.what() << std::endl;
    }
}

Esto nos permitirá hacer muchas definiciones de posibles elementos que serán plasmados en la plantilla, pero que no siempre estarán presentes y sólo se procesarán cuando aparezcan.

Un pequeño archivo XML

Para este ejemplo me voy a basar en un archivo sitemap.xml. El mismo tendrá un formato tal como este:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
  <url>
    <loc>http://dominio.com/section1</loc>
    <priority>0.70</priority>
    <changefreq>daily</changefreq>
    <lastmod>2015-02-13T15:32:42+0200</lastmod>
  </url>
  <url>
    <loc>http://dominio.com/section2</loc>
    <priority>0.70</priority>
    <changefreq>daily</changefreq>
    <lastmod>2015-02-13T15:32:42+0200</lastmod>
  </url>
  <url>
    <loc>http://dominio.com/section3</loc>
    <priority>0.70</priority>
    <changefreq>daily</changefreq>
    <lastmod>2015-02-13T15:32:42+0200</lastmod>
  </url>
...
</urlset>

En este caso quiero separar toda la parte de XML de mi código, por lo que el XML será un archivo aparte, lo leeremos y lo usaremos para mostrar la plantilla. Aunque en este caso nos encontramos con una lista de elementos que puede ser muy grande. Vamos a crear dos archivos, sitemap.xml:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
{%collection var=sites}}
  <url>
    <loc>{{sites.loc}}</loc>
{%if sites.prio}}    <priority>{{sites.prio}}</priority>{/if}}
{%if sites.changefreq}}    <changefreq>{{sites.changefreq}}</changefreq>{/if}}
{%if sites.lastmod}}    <lastmod>{{sites.lastmod}}</lastmod>{/if}}
  </url>
{/collection}}
</urlset>

y ahora nuestro archivo C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <string>
#include "silicon.h"

using namespace std;

int main()
{
  Silicon t = Silicon::createFromFile("sitemap.xml");
  try
    {
      std::vector<Silicon::StringMap> sites = { { { "loc", "http://dominio.com/section1" }, { "changefreq", "daily" } } ,
                        { { "loc", "http://dominio.com/section2" }, { "changefreq", "daily" }, { "prio", "0.2" } },
                        { { "loc", "http://dominio.com/section3" }, { "changefreq", "weekly" } },
                        { { "loc", "http://dominio.com/section4" }, { "changefreq", "weekly" }, { "lastmod", "2016-06-01T12:27:19+0200" } } };

      t.addCollection("sites", sites);

      std::cout << t.render()<<std::endl;
    }
  catch (SiliconException &e)
    {
      cout << "Exception!!! "<<e.what() << std::endl;
    }
}

De esta forma, deberá generarse un archivo XML con el formato especificado en el primer archivo, pero con los datos que tenemos en nuestro archivo C++. Tenemos que ver que dentro de la muestra de la colección hemos estado aplicando condiciones.

Generación de páginas web

Esta me la reservo para otro post, ya que podrá ser muy extensa, y tengo alguna que otra cosa preparada… Estad atentos.

Colaboración

Esta biblioteca podéis utilizarla como queráis para lo que queráis, sin garantías “as is”, podéis crear trabajos derivados, romperla, destrozarla y reconstuirla. Eso sí, aunque no es obligatorio, agradecería que me enviaseis cambios, correcciones, bugs, etc.
Hay partes del código que bien podrían ser reescritas, otras deberán ser mejoradas y actualizadas, pero poco a poco :)

Foto principal: Redd Angelo

The post Generando la salida de nuestros programas con plantillas en C++ con Silicon en pocas líneas appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Mig Salazar

Fluent Programming .NET

June 13, 2016 12:00 AM

El último año he dedicado la mitad de mi vida laboral a desarrollar interfaces para el manejo de registros de personas, i.e.: UI, plugins/widgets, web services, stored procedures, etc. Dentro de la información que se persiste, como parte de requerimiento de negocio, el cálculo automático de los diferentes tipos de identificación es indispensable.

Dado que los proyectos en los que estoy involucrado son consumidos en LATAM, he tratado con identificaciones de diferentes países, sin exagerar por mencionar:

  • México: RFC, CURP
  • Colombia y Chile: RUT
  • Panamá, Perú, Puerto Rico y Ecuador: DNI, RUC
  • Argentina: CUIT, CUIL, DNI, CDI

Y aunque esto es bastante normal, muchas aplicaciones que involucran información de personas requieren estos pequeños cálculos, puede llegar a convertirse en tu talón de aquiles.

Para México, es decir, para el cálculo del RFC, ya se contaba con una pequeña librería producto de un desarrollo in-house, que ha pasado de generación en generación, tras rotación y rotación, de un incontable número de desarrolladores. Existe código suelto, parches, código no comentado, en fin… es una librería a la cual no se le ha dado cariño prestado mucha atención.

No me atrevo a juzgar -porque sé que cometo un montón de errores- si ha sido o no un buen desarrollo, si cuenta con best practices, si tiene un performance aceptable, si es una librería testable, etc. Sin embargo, no puedo negar e ignorar, que me ha sido bastante complicado modificar esta librería; fué necesario debuggear línea a línea y un par de horas en estatus Don't disturb para entender qué/cómo/cuándo/dónde funciona. Y aún así, al día de hoy se siguen presentando problemas en ciertos escenarios muy particulares.

Además, -hasta donde sé- no hay evidencia de la base de la construcción de esta librería; es decir, las reglas para el cálculo no están alineadas a un documento oficial. Si a esto le sumamos el hecho de que la librería es de código cerrado, me ha parecido justo y necesario buscar alguna alternativa.

Búsqueda

Lo habitual, primero hacer un “barrido” rápido por la web google para identificar si alguien más se encuentra trabajando con el cálculo del RFC; podría sacar provecho y quizá alguna referencia.

Casi obvio, sí. Montones de implementaciones para el cálculo en diferentes lenguajes, los hay en: C, C++, VB, VB Script, Fox Pro, Progress, Java, Javascript, T-SQL, PL/SQL, Excel, Excel con macros, etc. Los más astutos te venden un programa con su respectivo wizard que realiza el cálculo.

La mayoría de las implementaciones que he encontrado, se quedan bastante cortas y con una lógica en su código algo extraña diferente.

En fin, concluí la búsqueda al encontrar una implementación en Java escrita por @josketres. Me ha parecido interesante y, por los argumentos basados en documentos oficiales, decidí basar mi código en esta implementación.

Resultado

El resultado, RFC Fácil .NET. El código fuente se encuentra en este repo.

No quiero entrar en detalles de la lógica y el contexto, pero me ha parecido interesante compartir el enfoque de la fachada de esta librería.

Fluent Interface

Fluent Interface es un estilo de implementación de código, si me permiten definirlo asi, para hacer más legible -o al menos en teoría- la programación. Este concepto viene atribuido por Martin Fowler por ahí del año 2005.

Lo interesante es el estilo al escribir código, la idea es que sea de manera fluida la invocación de métodos y sean apreciados como un conjunto de pasos o requerimientos para construir un objeto. Para los que conviven en el mundo de javascript, será bastante normal el término de Method Chaining y es este mismo enfoque el que se la dá a la POO con la técnica de Fluent Interface.

Contexto

Volviendo al tema, sabemos que para cacular el RFC es necesario tener de entrada la siguiente información de una persona:

  • Nombre(s)
  • Apellido(s)
  • Fecha de nacimiento

Lo habitual en POO sería, tener un constructor para inicializar un objeto Rfc, establecer propiedades a través de este y entonces realizar el cálculo. Visto desde el punto de vista cliente, se tendría algo así:

¿Cierto?

Ahora bien, supongamos un descuido al instanciar el objeto. Podría llevar a hacer algo como lo siguiente:

Es decir, dado que los primeros tres argumentos son de tipo string, no hay una forma de advertir al programador si debe ir primero el nombre y en segundo lugar el primer apellido o incluso alguna otra variación. Claro, excepto si se conocen o trabajan juntos viven juntos.

Es cierto, desde C# 3.0 podemos inicializar un objeto con las propiedades expuestas:

Sin embargo, para un constructor con un número relativamente grande de parámetros de entrada, sería bastante ilegible. Incluso, pensemos en una composición anidada; una inicialización de las propiedades complejas desde el constructor sería bastante tediosa e ilegible.

Implementación

El punto de inicio para RFC Fácil .NET, partirá de la clase RfcBuilder. Esta clase, contendrá los métodos chaining para la asignación de las propiedades.

Nótese que en cada método, después de establecer el valor de su respectiva propiedad, se retorna la misma instancia en cuestión con el uso de this. Este retorno, hará que el método se convierta en chainable.

Dado que cada método retorna una instancia de la clase RfcBuilder, requerimos un método de acceso para la instancia que inicialmente pensamos construir, es decir, la instancia de la clase Rfc.

Del código anterior, el método Build se encargará de orquestar las llamadas para el cálculo de cada parte del RFC. Lo importante a destacar aquí, es que este método retornará el tipo Rfc a través de la invocación de un método estático de la misma clase.

El contenido de la clase Rfc, quedaría algo como lo siguiente:

La intención de tener un constructor privado y acceder a este mediante un método estático, radica básicamente en evitar que el cliente construya una instancia de la clase Rfc con el operador new. De esta manera, se forzará a invocar el método Build, de la clase RfcBuilder, para mantener unúnico punto de acceso a la instancia.

Teniendo esto, nuestro código cliente que implementa el cálculo del RFC, se vería de la siguiente manera:

Ahh!, mucho mejor =D

Conclusión

No estoy del todo seguro si este estilo sea el más adecuado. Hay bastantes opiniones en contra de usar este enfoque; en general tiene una mala reputación.

De cualquier forma, creo que para el contexto en cuestión ha quedado bastante bien este estilo. Me parece que le dá mucha legibilidad, es práctico y minimiza el descuido al momento de invocar cada método. ¿No?

» Leer más, comentarios, etc...

Koalite

Lo peor de desarrollar software

June 12, 2016 05:06 AM

Imagínate que quieres ir a comer a un restaurante.

Después de buscar un poco, te decides por una arrocería que tiene una pinta estupenda. Cuando llegas, un atento camarero te trae la carta y eliges un arroz con bogavante que, según te aconseja el solícito camarero, es magnífico.

- Tardará unos 10 minutos en prepararse, queremos asegurarnos de que todo está a su gusto – te advierte.

Te resulta extraño porque sueles cocinar bastante arroz y sabes que tarda unos 20 minutos en estar listo, pero prefieres pensar que aquí son muy eficientes, porque la alternativa de que tengan el arroz hecho y lo vayan a recalentar te pone un poco nervioso.

Cuando pasados más de 20 minutos allí no ha aparecido arroz alguno, se lo reclamas al camarero. Éste, disculpándose amablemente, te explica que ha habido algunos problemas pero que ya casi está. Empiezas a enfadarte: estaba claro que no podían preparar el arroz en 10 minutos y, una de dos, o te están engañando o no tienen ni idea de hacer arroz, pero bueno, prefieres no pensar mucho en ello y disfrutar de tu arroz cuando llegue.

Y por fin llega el arroz. Con pollo.

- Esto es pollo. ¿Y el arroz con bogavante que había pedido? – preguntas al camarero.

- Vaya, lo siento. Tiene que haber sido un error. Le preparamos un bogavante y se lo añadimos a este arroz, así no tiene que esperar otra vez y podemos aprovechar parte del trabajo que hemos hecho ya.

Respiras profundamente mientras vas asumiendo que vas a comer arroz con pollo y bogavante. No suena muy bien, pero tienes suficiente hambre como para aceptarlo.

Cuando llega el bogavante, te mira con ojos desafiantes mientras avanza hacia ti chasqueando sus pinzas.

- ¡Está vivo! ¿Me ha traído un bogavante vivo?

- Verá, señor, vamos justos de tiempo, teníamos que haber terminado con su mesa hace un rato, pero su proyecto, digo, su comida, está resultando más complicada de lo que esperábamos y…

- Quiero mi bogavante. Y, por supuesto, lo quiero cocinado.

- Sí, señor, no se preocupe que esto lo solucionamos enseguida. Pondremos a nuestros cocineros certificados en bogavantes a trabajar en ello para asegurarnos de que reconducimos su proyecto, digo, comida.

Ahora sí, el bogavante tiene un aspecto mucho más apropiado y, por fin, puedes empezar a comer tu arroz (ya frío) con pollo (bastante reseco) y bogavante… ¿dulce? ¿Han cocido el bogavante en agua con azúcar? ¿A qué clase de experto certificado en bogavantes se le ocurriría hacer eso?

- Perdone, pero este bogavante está cocinado con azúcar. ¿Es que sus expertos no comprueban lo que están haciendo? ¿Por qué siempre me traen cosas sin sentido?

- Verá, nosotros creemos en trabajar estrechamente con el cliente durante la fase de testing y control de calidad para asegurar que la comida ofrece el valor añadido esperado. Además, habíamos reservado unas determinadas horas para atenderle y esto se está alargando más de lo previsto, por lo que comprenderá que tenemos que facturarle…

La realidad del desarrollo de software

Por desgracia, así funciona la mayoría del desarrollo de software, al menos en España.

Casi siempre que nos juntamos unos cuantos desarrolladores y nos quejamos de nuestro trabajo acabamos hablando de comerciales que sólo se preocupan por vender, de clientes que no saben lo que quieren (y tampoco están dispuestos a pagar un precio justo por ello) y de usuarios empeñados en “romper” nuestros preciosos sistemas.

Pero sobre todas esas cosas, si echo la vista atrás, lo que más frustración me ha producido ha sido la relación con otras empresas de desarrollo o con los departamentos de desarrollo de otras empresas.

Pocas veces he sufrido tanto como cuando yo he sido el cliente de un desarrollo.

Y eso que, se supone, algo sé del tema y debería estar preparado. O a lo mejor es justo por eso, porque sé algo del tema y sé que hay otras formas de hacer las cosas. En cualquier caso, cuando pienso en lo que debe de sentir alguien que contrata un desarrollo de software a la típica empresa del sector, me da lástima.

La mayoría del software que te entregan tiene una calidad ínfima.

Comprendo que definir correctamente la funcionalidad de un sistema no es una tarea fácil, requiere una buena comunicación y estoy dispuesto a asumir mi culpa como cliente por no haberla expresado bien o incluso por no haber sabido lo que realmente necesitaba, pero hay cosas que claman al cielo.

Aplicaciones que nadie se ha molestado en probar. No digo ya probar a fondo y cubrir cada caso extraño que pueda producirse, sino simplemente ver que se ejecuta y hace algo mínimamente lógico. No puede ser que se entregue una aplicación que a duras penas funciona en el caso más simple, y que, por supuesto, en cuanto fuerzas un poco, explota por mil sitios diferentes.

Los fallos de regresión están a la orden del día, y conseguir estabilizar un sistema se convierte en una auténtica labor de malabaristas; por cada cosa que se arregla se rompe otra.

Interfaces de usuario diseñados a patadas. No todos contamos con un excelente equipo de diseñadores para hacer interfaces de usuario atractivos y originales, pero qué menos que molestarse en mantener los controles alineados, revisar errores tipógraficos, ser consistente en los patrones de interacción. No hace falta ser un experto diseñador, con aplicar un poco de sentido común y poner algo de interés basta.

Usabilidad inexistente. ¿Que hay que obligar al usuario a dar 40 pasos para hacer una tarea que tiene que repetir 30 veces al día? ¿Que los mensajes de error son incomprensibles? ¿Que dejamos que el usuario destruya toda su información por no validar lo que introduce en el sistemma? Da igual, es su problema. Que aprenda a hacer las cosas bien y ser eficiente.

Gestión del ciclo de vida del producto nula. Lo he dicho antes: desarrollar es sólo el principio y entregar una aplicación es sólo un primer paso. Estoy cansado de que nadie haya previsto un plan para actualizarla, que no haya forma de diagnosticar errores en producción o que, ni siquiera, sea posible saber qué versión se está ejecutando en producción.

Y ojo, que en ningún momento estoy hablando de la calidad del código o la metodología empleada. Como cliente, me da igual la calidad del código, me importa el resultado que obtengo.

Me gustaría decir que estos problemas sólo se dan en determinados tipos de empresas, pero me los he encontrado trabajando con empresas grandes y con empresas pequeñas. Con empresas que tenían un organigrama tradicional, con una separación muy clara de roles entre comerciales, analistas, programadores, etc., y con empresas mucho más planas. Con empresas waterfall y con empresas agile. Con empresas desconocidas y con empresas “Business Golden Partner of the Century” del fabricante de turno. Con empresas caras y con empresas baratas.

Mi experiencia es que, desde el punto de vista del cliente, el panorama a la hora de contratar un desarrollo de software es desolador. No creo que se trate de un problema técnico. Tampoco de un problema comercial o de negocio. Es una cuestión cultural.

Y, sin embargo, funciona

Lo sorprendente de todo esto es que, al final, el mundo funciona. Y funciona a base de software. ¿Cómo?

Ha llegado un punto en que se asume que contratar un desarrollo de software será algo que requiera un esfuerzo enorme por parte del propio cliente para obtener un resultado final dudosamente aceptable. Como decía antes, es una cuestión cultural: hemos asumido que esto es lo que hay. Los clientes no son conscientes de que hay otra forma de desarrollar software.

Así, todos esos problemas que mencionaba antes y que a mi me parecen tan graves, no los son tanto para otros clientes. Están dispuestos a asumir que tendrán que perder mucho tiempo en conseguir que el proyecto arranque. Que, es cierto, nunca funcionará como las aplicaciones “de verdad”, porque, claro, es una aplicación “que nos hicieron a nosotros, y tiene sus cosillas“.

No sé en qué punto decidimos los clientes y usuarios que no importaba que el software fallase, pero es algo que tenemos bastante interiorizado. En otros productos esperamos que el funcionamiento sea siempre perfecto y predecible. En el software aceptamos que a veces “pasan cosas”.

Esa idea de que es normal que el software falle la hemos llevado a la contratación de un proyecto. Si contratases a un pintor para que te pintara la casa, no permitirías que te dejara las paredes mal acabadas, con manchas y ronchones. Tampoco verías normal que la pared que habías pedido azul acabase de color rojo. He visto muchos clientes de desarrollos de software que, cansados de luchar para que la pared fuese azul, acaban quedándose con la pared roja. O verde. O lo que sea, con tal cerrar de una vez el proyecto y acabar con esa pesadilla.

Esta gestión de expectativas entre empresas de desarrollo y clientes es lo que permite que el sistema siga funcionando. Sí, te he entregado un producto deficiente, pero es lo que hay. Todas las empresas somos iguales y esto funciona así. A veces me recuerda al mundo de las operadoras de telefonía. Todas te tratan mal, pero saben que pueden hacerlo porque son todas iguales y, vayas donde vayas, acabarás en la misma situación.

¿Todas? No. No todas las empresas son iguales.

Hay empresas que intentan cambiar esto. Que intentan actuar con profesionalidad y responsabilidad. Por desgracia, estas empresas tienen que luchar con la inercia de un mercado en el que cuesta mucho vender calidad porque, simplemente, el cliente no cree que eso exista.

Por eso me frustra especialmente esta situación.

Porque, además de afectarme como cliente, me afecta como desarrollador. Llega un punto en que lo podría convertirse en una ventaja competitiva (intentar hacer bien las cosas), queda anulado por el escepticismo de un cliente demasiado acostumbrado a que eso no existe.

No sé cuál es la forma de cambiar esto. A mi me resultaría más agradable vivir en un mundo en el que la gente se responsabilizase de su trabajo y actuase con profesionalidad, pero hay que ser realista y asumir que los incentivos económicos son los que mandan.

Mientras los clientes estén dispuestos a convivir con este tipo de desarrollos, estas empresas seguirán existiendo. Aun así, no pierdo la esperanza de que, algún día, si hay suficiente gente actuando con un poco de sentido común, alguien se dará cuenta de que se puede trabajar de otra manera, mucho más productiva y satisfactoria.

Hasta entonces, siempre podré seguir escribiendo rants absurdos como éste. No solucionan nada, pero al menos ayudan a desahogarse.

Posts relacionados:

  1. Cuánto daño han hecho… los arquitectos de software
  2. Desarrollar es sólo el principio
  3. La otra podredumbre del software

» Leer más, comentarios, etc...

Blog Bitix

La siguiente disrupción tecnológica, la convergencia

June 11, 2016 10:00 AM

La tecnología no para de avanzar, cada varios meses salen noticias de avances importantes. Algunos avances se convierten en realidad, otros tardan más en llegar, otros llegan pero no triunfan y de otros pasado un tiempo no se vuelve a oír hablar de ellos. Algunos cambios aunque mejoran lo existente son leves sin añadir nuevas posibilidades ni cambian los comportamientos de los usuarios o como interaccionan estos con la tecnología. Otros pocos son disruptivos y cambian de forma significativa el mercado de la tecnología junto con sus usuarios, estos cambios novedosos son capaces de hundir empresas líderes si no saben adaptarse o no los prevén al mismo tiempo que crean nuevos líderes en el mercado.

En el mundo de la tecnología cada nuevo procesador, tarjeta gráfica, SSD y otros componentes de un dispositivo se presentan prometiendo mejoras significativas en rendimiento y/o consumo de energía habitualmente entre un 20% y 90% sobre la generación anterior. Las mejoras de los componentes aunque significativas no suponen una disrupción en la tecnología, simplemente la hacen más rápida. El caso de los procesadores, tarjetas gráficas o SSD es una muestra, estos nuevos sistemas de almacenamiento aunque suponen una gran mejora sobre los discos duros mecánicos con una mucho mayor tasa de transferencia no modifican de forma disruptiva la tecnología para el usuario, si el ordenador en vez de iniciarse en un minuto y medio tarda 15 segundos aunque el SSD suponga una mejora significativa en el rendimiento de los ordenadores no es más que esperar más o menos tiempo, es una pequeña disrupción para los usuarios aunque grande para los fabricantes.

De las disrupciones que estoy hablando son las cambian significativamente la tecnología, la aparición del ordenador personal y como los aprovechó Microsoft e IBM no supo o no pudo, la aparición de las interfaces gráficas cuando solo existía la línea de comandos o estaban basadas en texto e iniciaron el dominio de Microsoft y Apple en la informática de consumo, de la aparición de los teléfonos móviles en la que en una época Nokia era el líder y como con la aparición de los teléfonos inteligentes al no adaptarse o preverlo sucumbió al menos tal y como era, de como 3dfx no pudo competir con las GPU modernas que NVIDIA popularizó con gran éxito. Algunas disrupciones importantes no son instantáneas pueden tardar algún lustro pero sin las compañías líderes no las ven venir ni se adaptan cuando quieren darse cuenta ya es demasiado tarde llegando a desaparecer o convertirse en poco relevantes. Algunas tecnologías prometedoras no tienen el éxito esperado como las pantallas de televisión 3D o curvas, un porcentaje grande de otros casos siguen el mismo camino, ¿alguien ha dicho blu-ray?, ¿smartwatch?, …

Microsoft Apple Linux

¿Cuál será la siguiente disrupción? Hacer cábalas sobre futuro es difícil y suele ser más propio del inicio de año pero aquí haré mi apuesta y a ver si acierto. En estos momentos hay varias novedosas que pueden cambiar significativamente el mundo de la tecnología una de ellas es la realidad virtual o la realidad aumentada de las holosens de Microsoft, muy de películas futuristas pero incómodas de usar para el usuario ya que requieren gafas en el caso de la realidad virtual que acaparan la visión y las holosens de Microsoft para la realidad aumentada no veo porque no vayan a seguir el mismo camino que las Google Glass, otro proyecto futurista de realidad aumentada es Google Tango que será un nuevo ámbito de acción para muchas empresas. De todas la que creo que más temprano que tarde llegará será la convergencia entre dispositivos móviles, tabletas, ordenadores e incluso smart tv.

Con la cada vez más capacidad de los dispositivos móviles que aumenta en un gran porcentaje en cada generación ¿cuando será el momento en que sean capaces de sustituir a otros dispositivos como ordenador y tabletas? Algunos móviles ya tienen 3 y 4GiB de memoria, sus procesadores más núcleos que un ordenador de escritorio, almacenamiento de 64GiB y 128Gib más que suficiente existiendo el almacenamiento en línea y externo para los dispositivos permanentemente conectados. Los procesadores de los dispositivos móviles ARM no está muy lejos del rendimiento de los procesadores de escritorio Intel Core ¿cuánto tiempo tardará en aparecer el primer ordenador de escritorio con procesador ARM? ¿Intel tiene que preocuparse por ARM? Yo creo que sí tiene que preocuparse por la convergencia en la que un procesador ARM no tardará mucho en tener suficiente capacidad (y II) para tareas básicas de escritorio mucho más barato de fabricar y más eficiente energéticamente. Intel hoy lidera la fabricación de procesadores de escritorio, ARM el diseño de procesadores de dispositivos móviles, la disrupción será que los procesadores ARM serán capaces de adentrarse en el escritorio e incluso en los servidores. ¿Apple en algún momento fabricará un MacBook con procesador ARM de los que ya incorpora personalizados en sus dispositivos móviles?

Los ordenadores de escritorio no se pueden transportar, los portátiles no pesan tanto siendo más manejables pero son incómodos y no acarrables en todo momento como los móviles por otro lado en los teléfonos inteligentes es incómodo escribir, copiar, pegar, trabajar con múltiples aplicaciones, navegar por internet y tiene una pantalla del alta resolución pero pequeña, digamos que hay una necesidad de unir ambos mundos que proporcione lo mejor de los dos. El ordenador de escritorio y portátiles de hoy serán irrelevantes salvo para algunos usuarios que requieran potencia extrema al igual que ocurre con las tarjetas gráficas dedicadas para jugadores exigentes, la convergencia hará que tengamos un único dispositivo para lo que hasta ahora utilizábamos varios para los casos de requerir mayor potencia surgirán dársenas o docks que proporcionen mayor capacidad gráfica y más opciones de conectividad. El smartphone sustituirá al ordenador de escritorio cuando podamos conectarlo a una pantalla externa junto con un teclado y ratón, el teléfono inteligente se convertirá en el dispositivo universal. El conector USB Type-C ya podría proporcionar la conectividad necesaria con pantallas, teclado, ratón y más dispositivos.

Cuando la diferencia entre el ordenador de escritorio y el dispositivo móvil sea poco significativa la convergencia será una realidad, cada año está más cerca no hay más que ver que ya hoy hay móviles con 4GiB de memoria la misma que algunos ordenadores de escritorio y portátiles de gama mediana y baja. Solo falta saber quienes del mercado tecnológico se adaptarán, perecerán, surgirán, perderán su relevancia y cual será el primero en comercializar un producto convergente.

Intel ARM

Intel lo tiene difícil, más con las recientes noticas del abandono de sus SoCs móviles, ya que los procesadores ARM son más baratos de fabricar y consumen menos energía lo que los hace más adecuados para los dispositivos móviles, salvo que el histórico Intel se adapte perderá gran parte de su relevancia en el mundo del hardware de cómputo en la misma medida que ARM la gane. Los fabricantes que adaptan los diseños ARM explorarán nuevos campos de mercado que hasta ahora no les era posible acceder. Los mejor posicionados Qualcomm, Samsung y quizá Nvidia tenga más éxito con sus procesadores ARM Tegra y en menor medida Freescale, Texas Instruments, Broadcom, y puede que veamos a AMD fabricar de forma masiva procesadores con arquitectura ARM en detrimento de x86-64, …

Por otro lado, la convergencia requerirá de software que se adapte a cada caso de uso, como dispositivo móvil y teléfono y como ordenador de escritorio y pantallas grandes como la televisión. Microsoft ya ha dado muestras de que está trabajando en la convergencia y si es la primera en hacerla realidad de forma útil para los usuarios seguirá durante alguna década más con su práctico monopolio en el escritorio y ganar una cuota mucho mayor entre los dispositivos móviles que hoy aún se le atraganta en detrimento de Google y Android y Apple e iOS. Google tiene las partes para iniciar la convergencia con Android en el ámbito móvil, por otro lado está Chromimum OS incorporados en sus Chromebooks en el ámbito de escritorio y si es capaz de juntar las piezas y no retrasarse frente a sus competidores puede mantener su amplia cuota de mercado en el ámbito móvil y ganarla en el escritorio desafiando la posición de Microsoft. De Apple aún no he oído noticias sobre la convergencia pero también tiene una buena posición con iOS por un lado y Mac OS X por el otro pero aunque se adelante a Microsoft y Google los precios de sus productos serán más elevados que lo que más tarde Google o Microsoft fabriquen y vendan con lo que hará que Microsoft no pierda su posición dominante si Google no se la cuestiona. Seguramente GNU/Linux irá detrás de la cresta de la ola, Ubuntu ya ha dado muestras de la convergencia y está desarrollando Snapy pero probablemente llegue más o mucho más tarde que los actores anteriores.

Esta batalla tecnológica de la convergencia forjará el nuevo equilibrio de fuerzas que se mantendrán durante algún lustro o década en la que esperemos los usuarios seamos en gran parte beneficiados por nuevos productos con nuevas posibilidades a precios asequibles… hasta una nueva disrupción. Está por ver quienes pierden su posición dominante, quieres la ganan y que nuevos contendientes surgen en este nuevo mercado que transformará el existente. Finalmente, todo esto no es más que una elucubración pero una muy plausible y no lejana de lo que finalmente se produzca.

» Leer más, comentarios, etc...

Arragonán

Semanas 414, 415, 416 y 417

June 06, 2016 11:34 PM

Casi un mes, nada menos que 4 semanas sin retro semanal, ahí es nada. La verdad que con tanto tiempo me ha costado tratar de recopilar lo hecho y resumirlo, han pasado muchas cosas en lo profesional y personal: Saraos, entrenamientos, celebraciones, no-celebraciones, partidos, cosas del día a día, algún viaje relámpago… hasta he sacado tiempo para hacerme cuenta en un servicio web de puretas que yo me sé. Pero bueno, en el acumulado ha ido bien la cosa :).

En estas semanas tuvimos por ahí en medio un Friday Dojo de Refactoring (que seguiremos este viernes). Nos sirvió como despedida del que ha sido el local de Hispalinux durante un porrón de años. Un local en el que han habido gran cantidad y variedad de eventos organizados por diferentes comunidades locales. He tenido que buscarlo, se inauguró en local nada menos que en 2006 y, aunque a temporadas ha estado algo parado, se le ha sacado mucho partido; pero bueno, seguiremos montando cosas en otros locales y espacios que nos cedan, eso seguro.

Con los CodingStones nos siguen saliendo cosas. Hemos cerrado con una Startup una colaboración a medio camino del mentoring y la consultoría, por el momento haremos una primera visita con algunas actividades y si todo va bien la colaboración se alargará en el tiempo. Mientras que por otro lado hemos trabajado con un par de posibles clientes para ver si encajamos para echarles una mano después del verano. Son 2 proyectos de temáticas muy diferentes, uno sobre trata movilidad y geolocalización mientras el otro combina arduinos y visualización de datos, ambos son relativamente pequeños y nos resultan muy atractivos.

Y aparte de algún side-project que se llevó algunos ratos de mi tiempo, estos fueron a grosso modo las cosas en las que trabajé:

  • En Outreach Tool estuve haciendo arreglos menores con vistas a algunos eventos de presentación de la metodología y la herramienta que da soporte. Ahora mismo la herramienta sigue siendo una hoja de cálculo bastante técnica que os podéis descargar cualquiera. Yo llevo un tiempo dándole vueltas a ver cómo podemos pasarlo a una aplicación web, mientras mis compañeros lo están rodando y van captando feedback.
  • Con los CodingStones hemos estado trabajando a tope en Conecta. Durante estas iteraciones hemos conseguido fortalecer una relación de confianza con el cliente, aportando cosas tanto en lo puramente técnico como en la visión de producto. Quizás no vayamos lo rápido que nos gustaría implementando funcionalidades, pero hemos puesto un estándar bastante alto en la calidad de lo que hacemos, tanto a nivel de código como de producto y por el momento vemos que el cliente lo percibe y valora. Como equipo también vemos que vamos mejorando poco a poco, el que tengamos todos una visión muy acorde con los valores y principios del Extremme Programming en mi opinión está facilitándolo mucho. Estamos sacando puntos de mejora muy interesantes en cada retrospectiva y revisión de código, incluso nos vamos inventado algunos artefactos un tanto locos para resolver ciertos escenarios que por el momento nos resuelven la papeleta.
  • También he ido dedicando algunos ratos a Mosica. En la parte de contenidos el mes de Mayo ha sido desastroso, no he dedicado apenas esfuerzo a ello. Mientras en la de desarrollo, he ido resolviendo algún problemilla que ha ido surgiendo, pero nada de los planes de evolución que tengo previstos hacer en algún momento.

Buena semana.

» Leer más, comentarios, etc...

Blog Bitix

Ofrecer contenido personalizado al usuario basado en su ubicación

June 06, 2016 05:00 PM

Cuando navegamos por internet el navegador envía mútiple información sobre nosotros y algunas páginas web recopilan esa información y la procesan para ofrecer contenido personalizado que creen nos resultaría de interés. Contenido con mayor relevancia para el usuario mejora la experiencia de usuario y la páginas web mejorarán su ratio de conversión y facturación. La información que proporcionamos sin ser conscientes son las cookies, la dirección IP, el navegador que usamos, el sistema operativo, nuestra resolución de pantalla, la hora a la que accedemos a la página, … en base a ella y aunque la información está impersonalizada sirve para identificarnos como inequivocamente usuarios. Con la dirección IP y usando una base de datos es posible obtener al menos el país desde el que se accede a una web y muy posiblemente la ciudad.

Linux
GNU
Java

Un usuario cuando navega por internet proporciona diversa información que las páginas web pueden utilizar para personalizar el contenido que le muestran. La información que el usuario proporciona es el navegador que utiliza, sistema operativo y dirección IP. Con las cookies las páginas web pueden almacenar información en su navegador que persista en varias sesiones. Amazon por ejemplo personaliza el contenido que ve el usuario cuando accede a la página de inicio mostrando diferentes categorías de productos en los que puede estar más interesado, por ejemplo, productos visitados en anteriores sesiones, relacionados o similares. Si el usuario ha visitado un producto con anterioridad es muy posible que esté interesado en comprar ese producto con lo que Amazon se lo muestra de nuevo en la siguiente sesión o le envía un correo electrónico al día siguiente como recordatorio. Una página de eventos, viajes, hoteles, restaurantes, museos, el tiempo, … puede mostrar información basada en la localización, por ejemplo, si alguien está en Madrid quizá esté interesando dependiendo de la búsqueda que haga en eventos, hoteles o museos en esa ciudad.

En Arch Linux al igual que en muchas otras distribuciones GNU/Linux hay unos comandos y unos paquetes que contienen una base de datos que en base a la dirección IP proporciona el país, ciudad, código postal y coordenadas geográficas de latitud y longitud, son geoip con información del país y geoip-database-extra para obtener información de la ciudad. La localización de un usuario también puede obtenerse usando una consulta que implique red de datos hacia algún servicio y si el usuario en su navegador lo permite proporcionar la información de su geoposicionamiento, la diferencia es que la petición que haga uso de red añade algo de latencia a la respuesta de la aplicación tampoco requieren pedir permisos al usuario para activar su geoposicionamiento. La información proporcionada por geoip quizá no sea tan exacta en todos los casos que los anteriores métodos pero más que suficiente en la mayoría. En caso de querer la mejor precisión se puede optar primeramente pedir al usuario que comparta su localizacion mediante el navegador, luego o en la primera petición hasta que el usuario comparta su posición por usar la base de datos de geoip, si esta no es exacta aunque seguramente proporcione al menos el país pero no proporciona la ciudad se puede optar por usar algún servicio que implique red.

Instalados los paquetes con las bases de datos de geoposicionamiento en la distribución GNU/Linux su uso desde la línea de comandos es el siguiente, indicando la dirección IP o nombre de dominio de la que queramos conocer su ubicación:

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/c521d486dd5740b5c9fa6144bde3bbc4/raw/geoiplookup-85.84.77.93.sh">geoiplookup-85.84.77.93.sh</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/c521d486dd5740b5c9fa6144bde3bbc4/raw/geoiplookup-8.8.8.8.sh">geoiplookup-8.8.8.8.sh</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/c521d486dd5740b5c9fa6144bde3bbc4/raw/geoiplookup-marca.es.sh">geoiplookup-marca.es.sh</pre></a></noscript>
Comando para obtener información de geoposicionamiento en base a la dirección IP

Otra opción es usar otra base de datos de geolocalización para direcciones IP, en vez de instalar un paquete en el sistema y usar el comando geoiplookup y procesar su salida con las bases de datos de MaxMind GeoLite2 para paises y ciudades dispondremos de una API accessible desde el lenguaje de programación que prefiramos. En este ejemplo usaré Java pero hay bindings para los lenguajes más populares.

Este sería el código para obtener la información de forma más sencilla que lanzar un proceso del sistema y parsear su resultado, además con GeoLite2 la aplicación no necesitará que el sistema tenga un paquete instalado y será más autocontenida. La base de datos de geolocalización se proporciona en un archivo que es posible distribuir con la aplicación.

En el siguiente ejemplo no incluyo la base de datos en el código fuente del proyecto ya que ocupa casi 65MiB. Descargada, descomprimida y ubicada en el directorio src/main/resources la aplicación se iniciar con el comando ./gradlew run.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/74bd3f93225874e9fa35918515f5ec06/raw/Main.java">Main.java</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/74bd3f93225874e9fa35918515f5ec06/raw/build.gradle">build.gradle</pre></a></noscript>
Información de geoposicionamiento en base a la dirección IP con GeoLite2

GeoLite2 tiene una licencia Creative Commons Attribution-ShareAlike y no tiene coste, MaxMind proporciona además otras bases de datos más completas pero con un coste, 50$ para la base de datos de paises más 24$ para las actualizaciones y 370$ para la base de datos de ciudades más 100$ para las actualizaciones.

En una aplicación web Java en la interfaz ServletResquest y con el método getRemoteAddr() obtenemos la dirección IP del usuario, ya solo nos queda lanzar un proceso del sistema desde Java que invoque al comando geoiplookup con la dirección IP obtenida o usar la API Java u de otro lenguaje de MaxMind GeoLite2, obtener la salida del proceso, interpretarla y hacer con ella lo que queramos hacer en la aplicación. En una aplicación web adicionalmente somos libres de usar la API de geoposicionamiento implementada en los navegadores.

Proporcionar contenido personalizado al usuario probablemente ayuda a mejorar la conversión de un sitio de comercio electrónico y la experiencia del usuario ofreciéndole productos o servicios en los que de alguna forma esté interesado ya sea como en este caso basado en su ubicación, pero como en el caso de Amazon según las visitas anteriores y en otros podría ser en base al sistema operativo o navegador como hace Google cuando accedemos a su buscador indicándonos que nos instalemos Chrome si usamos Firefox.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.

» Leer más, comentarios, etc...

Poesía Binaria

Instalar múltiples versiones de PHP y extensiones con phpfarm en Ubuntu/Mint/Debian…

June 06, 2016 10:48 AM

photo-1441749074938-1c6782303919
Si llevas varios años trabajando con este lenguaje de programación. Tal vez se te ha presentado un pequeño problema: tienes varios desarrollos a lo largo del tiempo y tienes código en una versión de PHP antigua que no es compatible con versiones nuevas. Y, por otro lado, mientras mantienes una versión de producción de otro proyecto (para PHP 5.5 o PHP 5.6), quieres empezar a hacer pruebas para ver cómo se comporta con PHP7, y todo ello sin morir en el intento.

En mi día a día, muchas veces me enfrento a esa situación. Hay programas que no voy a tocar nunca, ni estoy dispuesto a ello, hechos con versiones antiguas de PHP y que ahora mismo están corriendo en PHP 5.3 sin problema. Son programas de esos que el día que me ponga con ellos, los quiero reescribir enteros, y lo voy dejando, lo voy dejando… aunque en ocasiones necesitan un arreglo (¡ no, un array no ! Un arreglo, de arreglar, o bueno, reparación, parche…) y tengo que poder ejecutarlos en local.

Entonces, en necesito constantemente en mi ordenador tres versiones instaladas, PHP 5.3, PHP 5.5 y PHP 7. Una solución puede ser crear máquinas virtuales o usar vagrant para cada uno de los proyectos. Aunque por un lado puedo desactivar máquinas y olvidarme de ellas cuando no están, incluso tenerlas en un disco duro externo para que no estén ocupando, por otro lado, necesito replicar varias veces un software que ya tengo (sistema operativo, servidor web, bibliotecas de sistem, etc), y todo esto consume disco, memoria y procesador cuando está cargado. Podría utilizar tecnologías como LxC o docker para utilizar en local estos servidores.

Yo opté por utilizar phpfarm y, aunque es un proyecto antiguo, hace lo que tiene que hacer: nos proporciona un entorno en el que compilar y utilizar distintas versiones de PHP de forma razonablemente fácil. Incluso se defiende bien para compilar las últimas versiones de PHP sin problemas.

Aunque los siguientes pasos puedan parecer muy complejos, lentos y costosos si no estás acostumbrado a compilar software en tu ordenador, es más sencillo de lo que parece. Esta instalación la he hecho en Linux Mint 17.3 Rosa, aunque debería funcionar sin problemas en Ubuntu y en Debian (si no tienes sudo, hazte root y quita el sudo).

Preparando el entorno para compilar PHP

Si has compilado algo anteriormente, seguramente ya tendrás instaladas las build-essential, pero para instalarlas:

$ sudo apt-get build-essential

Ahora, vamos a instalar algunas dependencias para compilar PHP, serán algunas bibliotecas que se requieren para poder realizar la compilación con éxito. Bueno, también he incluido git, ya que descargaremos phpfarm desde su repositorio de github

$ sudo apt-get build-dep php5
$ sudo apt-get install libmcrypt-dev libc-client2007e-dev git

Como servidor web voy a utilizar Apache 2.4 en modo CGI (podemos utilizar otras opciones), para ello debemos instalar también:

$ sudo apt-get install libapache2-mod-fcgid

Y activarlo

$ sudo a2enmod fcgid

Instalando phpfarm

Ahora clonamos el repositorio desde github. Yo lo he copiado todo en /opt/ (hace mucho que vi en una guía que alguien lo instalaba ahí y me gustó la idea, en lugar de hacerlo en un directorio de usuario). Así que todo lo que queda de tutorial lo haremos desde esa carpeta.

$ sudo git clone https://github.com/cweiske/phpfarm.git /opt/phpfarm

Los siguientes pasos se repetirán para cada una de las instalaciones que vayamos a hacer de PHP. Por lo que, para esta primera instalación lo pondré con más detalle, en las siguientes instalaciones iré un poco más rápido.

Configurando y compilando PHP

A mí me gusta hacer una configuración individual por cada versión de PHP que instalo, o al menos, hasta la versión menor. Por ejemplo, uno para PHP5.3, otro para PHP5.5 y otro para PHP7.0, a lo mejor necesitamos llegar hasta la revisión en alguna instalación puntual (5.5.19), pero bueno, tenemos la opción. Esta configuración irá en un archivo llamado custom-options.sh dentro de /opt/phpfarm/src . Si queremos:

  • Una configuración global para todas las compilaciones de PHP, utilizaremos custom-options.sh
  • Una configuración para todo lo que sea PHP 5 (5.1, 5.2, 5.3, …) usaremos custom-options-5.sh
  • Una configuración para todos los PHP 5.3 (5.3.1, 5.3.2, 5.3.10, …) usaremos custom-options-5.3.sh
  • Una configuración particular para una revisión en concreto (5.3.19) usaremos custom-options-5.3.19.sh

Además, este archivo no tiene por qué tener permiso de ejecución. En este archivo incluiremos las opciones que vamos a pasarle al configure de PHP. Es decir, los diferentes elementos a los que daremos soporte en nuestra compilación. Muchos serán los módulos que se incluirán (por ejemplo exif, gd, mbstring, ttf, openssl, pear…), un poco más adelante os diré cómo averiguar las diferentes opciones que soporta una versión de PHP. En este caso crearemos custom-options-5.3.sh con el siguiente contenido (delante de cada enable y cada with hay dos guiones seguidos – -):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# You can override config options very easily.
# Just create a custom options file; it may be version specific:
# - custom-options.sh
# - custom-options-5.sh
# - custom-options-5.3.sh
# - custom-options-5.3.1.sh
#
# Don't touch this file here - it would prevent you to just "svn up"
# your phpfarm source code.

configoptions="\
--enable-bcmath \
--enable-calendar \
--enable-exif \
--enable-ftp \
--enable-gd-native-ttf \
--enable-mbstring \
--enable-pcntl \
--enable-soap \
--enable-sockets \
--enable-wddx \
--enable-zip \
--enable-sysvshm \
--enable-sysvsem \
--enable-sysvmsg \
--enable-cgi \
--with-openssl \
--with-zlib \
--with-pear \
--with-pecl \
--with-gettext \
--with-imap \
--with-imap-ssl \
--with-kerberos \
--with-pdo-mysql \
--with-mysqli \
--with-mysql \
--with-curl \
--with-gd \
--with-jpeg-dir=/usr/lib \
--with-mcrypt"

Una opción interesante puede ser activar “–enable-fpm” si queremos configurar nuestro servidor con este soporte (experimental en 5.3), pero nos permitirá correr servidores de PHP que luego se podrán comunicar con nuestro servidor web.

El siguiente paso es compilar la versión de PHP que queremos. Para ello, nos situamos dentro de /opt/phpfarm/src y ejecutamos:

$ sudo ./compile 5.3.29

Esto trabajará solo un rato. Él sólo se descarga la versión elegida de PHP desde varias fuentes (según esté disponible), hace el configure, make y lo pone todo en su sitio. Normalmente si hemos seguido las instrucciones, debería terminar sin problemas. Aunque si os da algún problema debemos leer bien el error de la compilación. Muchas veces si buscamos el error en Internet nos dirá cómo solucionarlo, porque puede que nos falte alguna biblioteca por instalar o que haya algo mal escrito en el archivo custom-options.sh, aunque os animo a escribir un comentario con el fallo que os da a ver si entre todos lo podemos arreglar.

Configurar Apache

Ya tenemos la versión instalada. En este punto, de cara al servidor web, ya que haremos la configuración con CGI, crearemos dentro de /opt/phpfarm el directorio cgi-bin:

$ mkdir cgi-bin

y allí crearemos un archivo llamado php-5.3 (como root). Y, con un editor de texto (nano, gedit, vi, emacs…) añadiremos el siguiente contenido:

1
2
3
4
5
6
7
#!/bin/sh
PHP_FCGI_CHILDREN=3
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS

exec /opt/phpfarm/inst/bin/php-cgi-5.3.29

Si os fijáis, en la última línea ponemos la ruta del archivo ejecutable de php-cgi correspondiente a la versión que queremos configurar. Ahora configuraremos el VirtualHost de Apache añadiendo las siguientes líneas (ir a esta web para ver un virtualhost completo):
En el vhost incluir:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        <Directory /home/usuario/webs/miweb53/>
                Options +Indexes +FollowSymLinks -MultiViews +ExecCGI
                AddHandler php-cgi .php
                AllowOverride All
                AddHandler fcgid-script .php .php5 .phtml
                FcgidWrapper /opt/phpfarm/cgi-bin/php-cgi-5.3 .php
                FcgidWrapper /opt/phpfarm/cgi-bin/php-cgi-5.3 .php5
                FcgidWrapper /opt/phpfarm/cgi-bin/php-cgi-5.3 .phtml
                Require all granted
        </Directory>
        <Directory "/opt/phpfarm/cgi-bin">
                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                AllowOverride None
                Require all granted
        </Directory>

Tras esto, sólo queda recargar la configuración de Apache:

$ sudo service apache2 reload

Ejecutable para PHP en línea de comandos

Esto será un simple enlace en /usr/local/bin (debemos asegurarnos de tener esta ruta en nuestro PATH, para ello, en consola podemos hacer $ echo $PATH). Con esto vamos a hacer que la ejecución de php-5.3 sea global en nuestro sistema:

$ sudo ln -s /opt/phpfarm/inst/php-5.3.29/bin/php /usr/local/bin/php-5.3

De la misma manera podemos crear enlaces a los diferentes ejecutables que hay en ese directorio.

Si además queremos que al ejecutar php (a secas, a nivel de sistema) se haga con esta versión:

$ sudo ln -s /opt/phpfarm/inst/php-5.3.29/bin/php /usr/local/bin/

Instalando APC con PECL

Una extensión que suele usarse mucho es APC como caché de código y datos. Y suele ser obligatoria en muchos scripts. Para instalarla, iremos a /opt/phpfarm/inst/php-5.3.29/bin/ y ejecutaremos:

$ sudo pecl install apc

Esto nos hará varias preguntas para configurar la extensión (podemos decir que sí a todo, o darle a enter), normalmente no suele haber problemas si la versión del módulo no es muy antigua.

Luego editamos /opt/phpfarm/inst/php-5.3.29/lib/php.ini e incluimos al final:

1
extension=apc.so

Instalando otras versiones de PHP

Yo instalo también otra versión la 5.5.35, para ello creo un custom-options-5.5.sh con un contenido muy parecido al anterior (eliminamos -with-pecl porque ya viene incluido y este flag no se reconoce):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# You can override config options very easily.
# Just create a custom options file; it may be version specific:
# - custom-options.sh
# - custom-options-5.sh
# - custom-options-5.3.sh
# - custom-options-5.3.1.sh
#
# Don't touch this file here - it would prevent you to just "svn up"
# your phpfarm source code.

configoptions="\
--enable-bcmath \
--enable-calendar \
--enable-exif \
--enable-ftp \
--enable-gd-native-ttf \
--enable-mbstring \
--enable-pcntl \
--enable-soap \
--enable-sockets \
--enable-wddx \
--enable-zip \
--enable-sysvshm \
--enable-sysvsem \
--enable-sysvmsg \
--enable-cgi \
--with-openssl \
--with-zlib \
--with-pear \
--with-gettext \
--with-imap \
--with-imap-ssl \
--with-kerberos \
--with-pdo-mysql \
--with-mysqli \
--with-mysql \
--with-curl \
--with-gd \
--with-jpeg-dir=/usr/lib \
--with-mcrypt"

Compilamos como antes:

$ ./compile 5.5.35

Cuando termine el proceso, instalamos APCU (nueva versión con compatibilidad con APC). Debemos asegurarnos de instalar la versión 4.0.10 que es la última compatible con PHP5.5:

$ sudo ./pecl install apcu-4.0.10

De la misma manera al final del fichero /opt/phpfarm/inst/php-5.5.35/lib/php.ini incluimos:

1
extension=apcu.so

De la misma manera, podemos configurar el VirtualHost que trabajará con PHP5.5 creando un lanzador en /opt/phpfarm/cgi-bin/php-5.5 y cambiando la ruta también en Apache, además, crear los enlaces a php-5.5 en /usr/local/bin.

Instalando PHP7

Por el momento, las opciones de compilación de PHP7 pueden ser las mismas que para PHP5.5, incluso podemos hacer:

$ sudo ./compile 7.0.6

sin problema (la 7.0.6 es la última versión estable a día de hoy, y no descarto que tengamos que modificar el custom-options.sh para futuras versiones). La configuración del virtualhost y los enlaces, todo se mantiene de forma similar a como veníamos haciéndolo hasta ahora.

Versiones de PHP que no se pueden descargar

Tal vez queramos instalar una versión antigua, o muy nueva (una RC por ejemplo), que ya no (o todavía no) está en los repositorios oficiales de PHP. Lo que podemos hacer es descargarla a mano en formato tar.bz2 y darle el siguiente nombre:

php-version.tar.bz2

Ese archivo lo copiamos en /opt/phpfarm/src/bzips luego podemos hacer el ./compile [version] como hasta ahora. Todo lo demás se mantendría igual.

Experimentos y otros detalles

Experimentar con las configuraciones

Ahora llega el momento de jugar. Por ejemplo, ¿qué otras opciones podemos darle a PHP para compilar? Esas famosas opciones para el configure. En esta guía, he puesto algunas opciones genéricas que en mi caso funcionan bien, pero tal vez necesites un módulo adicional, o soporte para alguna tecnología que utilizas. Para ello, viene bien saber todo lo que hay disponible. Eso lo podemos averiguar si después del ./compile estamos atentos y paramos el proceso (Control-C) una vez descomprimido el archivo descargado (si dejamos que se compile todo, simplemente tardaremos más). Una vez parado el proceso entramos en /opt/phpfarm/src/php-5.5.35 (o la versión que queramos) y allí ejecutamos:

$ ./configure –help

Será muy largo, por lo que tal vez quieras paginarlo con less o more:

$ ./configure –help | less

Esto implicará mucha lectura por tu parte para saber qué es cada cosa. Muchas veces, requerirá algo de búsqueda por Internet y, tal vez sea necesario instalar alguna biblioteca en el sistema antes de poder compilar. De todas formas, os animo a probar y a comentar vuestras configuraciones propias.

Varias versiones para un mismo proyecto

Puede que un proyecto ejecute normalmente con PHP5.5, pero que para ciertas operaciones intensivas utilice PHP7.0, es sencillo, podemos configurar el VirtualHost para que dos directorios diferentes utilicen versiones diferentes de PHP. Será Apache el que se encargue de hacer el cambio.

Cambiar la versión de PHP en consola

Para consola, podemos crear un enlace de la siguiente manera:

$ sudo ln -s /opt/phpfarm/inst/current-bin /usr/local/bin/php

y

$ sudo ln -s /opt/phpfarm/inst/switch-phpfarm /usr/local/bin/

De esta forma, podremos ejecutar:

$ sudo switch-phpfarm

y ver las versiones disponibles, y del mismo modo:

$ sudo switch-phpfarm 5.5.35

Para hacer que el ejecutable php a nivel de sistema sea el de la versión 5.5 (y cambiar de versión cuando queramos).

Foto principal: Evelyn Paris

The post Instalar múltiples versiones de PHP y extensiones con phpfarm en Ubuntu/Mint/Debian… appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Sponsors

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin