Archivo

Archivo para la categoría ‘General’

Linux on Movies: Person of Interest usa GNOME

Jueves, 5 de Abril de 2012 Gaspar Fernández 2 comentarios

En esta serie, Person of Interest (Vigilados en español) protagonizada por Jim Caviezel y Michael Emerson, salen escritorios Gnome 2 por todas partes, con diferentes temas.

Aunque no se termina de ver claro, hay algunas veces que se perfila algo, es un escritorio muy personalizado que siempre tiene textos de terminal o en hexadecimal en movimiento (porque los mejores informáticos lo hacen así)… pero en la barra inferior, tiene un texto “Applications”, “Places”, “System”, os suena… porque a mi me recuerda horrores a GNOME 2.

No dejo momentos concretos porque desde el primer capítulo se puede ver un escritorio así en el ordenador de uno de los protagonistas y escritorios parecidos en otros ordenadores que van apareciendo.

point_gnome
Por ejemplo esto es del episodio 9 de la primera temporada. Minuto 11:56 y esto del 31:28 (no hagáis mucho caso a las direcciones IP, porque parece que ese tema lo llevan un poco mal)
point_gnome2

Y este pantallazo del capítulo 13 de la primera temporada. Minuto 30:15 (aunque salen pantallas parecidas varias veces) me recuerda a Unity:
point_unity

C.I. XVII: Historia de C por Denis Ritchie, tareas elefante, Raspberry PI, NVIDIA y la Linux Foundation, sed, urandom en python

Domingo, 11 de Marzo de 2012 Gaspar Fernández 1 comentario

Mucho tiempo sin una sección de estas, y traigo contenidos muy variados:

Problema en Acer Aspire One AOA150: No carga la batería

Jueves, 1 de Marzo de 2012 Gaspar Fernández Sin comentarios

chocolate
Ha llegado a mis manos un Acer Aspire One ZG5 AOA150, tras un tiempo sin usarse, al enchufarlo todo va bien, pero cuando se trata de funcionar con él por batería, resulta imposible, es más, incluso estando enchufado, al cabo de un tiempo se apaga (sólo cuando tiene la batería puesta), y por supuesto la batería no carga, es más, ni se calienta. Todo apunta a que la batería está mal.

Estos portátiles tienen un circuito de protección de la batería, y se desactiva su uso cuando se lleva un tiempo sin usar. Después de desarmar el portátil y que luego me sobrara un tornillo, aunque son fáciles de desarmar, de hecho tienen que ser desarmados para cambiar la RAM o el disco duro, que es lo reemplazable. Después de probar otra batería, sin éxito, me da por mirar si hay actualizaciones de BIOS en la web, en efecto hay.

Pues vamos a reemplazar la BIOS. Aunque como buen fan del software libre, viendo las dos opciones que hay: desde Windows o desde MS-DOS. Me decido por la segunda. Por experiencia y sabiendo cómo es Windows yo no me fiaría reescribiendo la BIOS desde ese SO, el más mínimo fallo y perdemos el ordenador. Aunque actualmente, como fan del software libre (y porque no hay BIOS libre para este equipo, si no intentaríamos escribir esta). De la página anterior me bajé el 3310 y siguiendo este artículo podemos crear un disco con FreeDOS. En ese mismo pendrive USB podemos grabar los archivos para reprogramar la BIOS desde MSDOS. Tras ello, arrancar el netbook con el pendrive de FreeDOS y cargar el programa para reprogramar.
Apaga el Netbook, enciéndelo y la batería debería estar cargando, pero mejor pregúntaselo al sistema operativo:

$cat /proc/acpi/battery/BAT0/state

Si pone charging, la cosa va bien. De hecho ahora este netbook está funcionando como un campeón.

Aunque pongo en el artículo que es especial para este modelo de Netbook, creo que esto vale para muchos portátiles de Acer. Si nos aseguramos bien de que la BIOS corresponde al modelo que tenemos delante no hay ningún problema en reprogramarla.

Creando una unidad USB de arranque DOS (FREEDOS) con software libre

Lunes, 27 de Febrero de 2012 Gaspar Fernández Sin comentarios

dos
¿Echas de menos tener un sistema MS-DOS? Si eres de los que ya llevas tiempo en el mundo de la informática, esta pantalla de arriba te resultará familiar. Aquel modo texto a 80×25, clásica que podíamos ver en los ordenadores antiguos. Y es que, a veces, puede ser muy útil disponer de un sistema de estos, ya sea para una máquina virtual, o para nuestro ordenador, donde podemos ejecutar las instrucciones que nos vengan en gana sin preocuparnos de que al sistema operativo le gusten o no, para investigar, para revivir viejos tiempos con un antiguo juego, o analizar un programa que sólo funciona en ese sistema, que aún los hay, y debemos portar la información a programas más nuevos. Casi siempre por necesidad, porque donde se ponga “ls” que se quite “dir” :)

Esto lo podemos hacer de dos formas distintas, con makebootfat, nativo para GNU/Linux, o emulando FreeDOS y utilizando sus herramientas (elegir sólo un método):

Método nativo para GNU/Linux

Lo primero que tenemos que hacer es instalar makebootfat y syslinux. En una distribución tipo Debian/Ubuntu/Linux Mint podemos hacer lo siguiente:

$ sudo apt-get install makebootfat syslinux

Una vez tenemos instalados los paquetes, después de asegurarnos de que el pendrive (unidad USB), no tiene nada importante, debemos formatearlo. Usaremos el sistema de archivos FAT16, por lo que el tamaño máximo de la unidad será de 2Gb. Si la unidad es pequeña (menos de 2Gb, como hemos visto antes), habrá que cambiar el tipo de partición solamente), si la unidad es más grande (debemos eliminar la partición existente, ya que supongo que tu pendrive es sólo una unidad, y luego crear una partición pequeña).

Debemos sustituir la sdX por el dispositivo de nuestra unidad USB. Podemos verlo haciendo:

$ dmesg | tail

nada más enchufar la unidad. Luego hacemos:

$ sudo fdisk /dev/sdX

Lo primero será eliminar la partición (sólo si tenemos un pendrive de más de 2Gb), lo hacemos pulsando d [INTRO]

Luego creamos una nueva partición (n [INTRO]):

  • Lo primero que nos pide es si será (p) principal o (e) extendida, elegimos princpal
  • Lo siguiente es el número de la partición, elegimos el 1
  • Luego dónde empieza (damos a enter, ponemos el valor por defecto)
  • Lo siguiente el tamaño. Escribiremos +100M para darle 100Mb a la unidad, podemos darle hasta 2Gb

Lo siguiente es elegir el tipo de partición, pulsamos la letra t [INTRO] y luego elegimos el tipo 6 (FAT16), podemos ver con L un listado de tipos de partición.

Tras todo esto, escribimos los cambios con w [INTRO]

Ya tenemos una unidad FAT16 en nuestro pendrive, ahora la formateamos:

Tenemos que formatear sdX1 (X depende del dispositivo donde nuestro sistema lo detecte)

$ sudo mkfs.vfat /dev/sdX1

Ahora debemos bajar el siguiente archivo:
kernels.zip, lo grabamos en /home/usuario/trabajo/ .
Ahora vamos a esta página, y descargamos la imagen de un disquette de arranque de FreeDOS, por ejemplo el disquette de 2.88Mb, que es el que trae algunos comandos. Lo copiamos también en /home/usuario/trabajo/
Y desde ahí:

$ unzip kernels.zip # Descomprimimos el archivo
$ mkdir pendrive # Creamos una nueva carpeta
$ cp source/ukernel/boot/fat*.bin . # Copiamos los kernels en el directorio de trabajo
$ cp /usr/lib/syslinux/mbr.bin . # Copiamos la imagen del mbr en el directorio de trabajo
$ gunzip FDSTD.288.gz # Descomprimimos la imagen de disco
$ sudo mkdir /mnt/floppy # Creamos un punto de montaje para el disquette
$ sudo mount -t vfat -o loop FDSTD.288 /mnt/floppy # Montamos el disquette
$ cp -r /mnt/floppy/* pendrive/ # Copiamos todos los archivos del disquette al directorio de nuestro pendrive
$ sudo umount /mnt/floppy # Desmontamos el disquette

Ya lo tenemos todo listo, sólo falta crear el disco de arranque, para ello ejecutamos:

$ sudo makebootfat -o /dev/sdX -E 255 -1 fat12.bin -2 fat16.bin -3 fat32lba.bin -m mbr.bin pendrive

Esto escribirá en el pendrive /dev/sdX (sin el 1):

  • -E 255 detecta la unidad BIOS, FAT12 y FAT16 requieren poner el valor correcto para poder arrancar, 255 autodetecta
  • -1, -2, -3 son los kernels de fat12, fat16 y fat32
  • -m, define la imagen del mbr
  • pendrive, copia todos estos archivos

Ya podemos retirar el pendrive para usarlo y arrancar con él.

Emulando FreeDOS

Lo primero es decargar un disquette de arranque de Freedos desde aquí, y descargamos la imagen de un disquette de arranque de FreeDOS, por ejemplo el disquette de 2.88Mb, que trae más cosas. (Ver en la explicación de arriba cómo descomprimir la imagen).

Luego instalaremos qemu. Desde Debian/Ubuntu/Mint:

$ sudo apt-get install qemu

Ahora arrancaremos qemu para emular FreeDOS utilizando como disco duro el pendrive (si está vacío mejor):

$ qemu -hda /dev/sdX -drive file=FDSTD.288,if=floppy

Esto arrancará en una ventana FreeDOS desde la imagen de disquette, lo que tenemos que hacer es utilizar fdisk (como el de MS-DOS para eliminar la partición existente y crear otra nueva), format para formatear el pendrive, en este caso podemos hacer FORMAT C: sin miedo, ya que el disco duro es el pendrive, y luego desde A: hacer “sys C:” para copiar el sistema base al disco duro. Es recomendable copiar luego con copy todos los archivos del disquette.

Una vez hecho esto, podemos cerrar qemu, sacar el pendrive y utilizarlo

Menos tiempo para actualizar

Lunes, 13 de Febrero de 2012 Gaspar Fernández 2 comentarios

A partir de ahora voy a tener mucho menos tiempo para actualizar el blog, no quiero dejar de publicar, sólo bajará la frecuencia de las publicaciones, ya que no puedo mantener el ritmo. A pesar de que tengo muchos artículos en el tintero, voy a tener que retrasarlos aún más por motivos personales y laborales. Seguiré por aquí, además, tenéis la página de Facebook donde voy publicando las novedades del blog, podéis seguirme en Twitter (@blakeyed), aunque sea un nombre raro, pero soy yo.

Generar texto e implantarlo en una imagen desde PHP

Viernes, 10 de Febrero de 2012 Gaspar Fernández 1 comentario

En ocasiones, se puede presentar la necesidad de introducir en nuestros proyectos una imagen cuyo contenido sea un texto, y sobre todo necesitamos integrarlo dentro de nuestro contenido, intentando que no se note que es una imagen, a no se que seleccionen el contenido para copiarlo.

Una de las principales utilidades de esto es evitar el SPAM al escribir nuestra dirección de e-mail en una web. Muchos clientes prefieren enviar un e-mail en lugar de utilizar un formulario de contacto y tenemos que satisfacerles, sin arriesgar la seguridad de nuestro sistema, en el sentido de que hay cientos de motores que se dedican a rastrear webs en busca de direcciones de e-mail (lo cual es muy sencillo de hacer con expresiones regulares, por ejemplo).

Tenemos que estudiar bien cómo hacemos el script, ya que la entrada de datos es esencial. Sería improductivo hacer un script cuya llamada fuera:

1
<img src="scriptGenerador.php?texto=midireccion@miservidor.com" />

Ya que un motor se enteraría de que eso es una dirección de correo igualmente. Por lo que yo sugiero algunas opciones:

  • Para simplificar, podemos codificar el texto, por ejemplo, en base 64, el e-mail anterior quedaría así:bWlkaXJlY2Npb25AbWlzZXJ2aWRvci5jb20 y sería más complicado de detectar, aunque es nuestra responsabilidad hacer la conversión. Además, si en cualquier momento queremos identificar el texto que pusimos, en cierto punto del código debemos hacer la conversión inversa. Por otra parte, aunque es difícil que algún motor se dedique a convertir el texto en base64 a binario de nuevo, es posible.
  • Otra posibilidad es, si sólo vamos a escribir un sólo texto de esta forma, implantarlo dentro del archivo php que genera la imagen, como una variable del propio código, así no debemos escribir nada cuando llamemos al script. Si tenemos que cambiar el texto, basta con editar el script
  • Si, por el contrario, vamos a escribir varios mensajes, podemos asignar una clave a cada uno, por ejemplo, un número o una cadena de texto corta, y en nuestro script hacer corresponder ese número con el texto en cuestión.

Aquí vamos a hacer un ejemplo de la tercera opción. Aunque podemos extender el ejemplo usando bases de datos (si tenemos que introducir muchos mensajes, o muchas direcciones de e-mail diferentes), aquí vamos a crear un array en PHP para hacer corresponder la clave introducida con el valor (el texto que de verdad escribimos).

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
<?php
  // Con esta función calculamos la anchura, altura del texto y dónde está la baseline de nuestro texto
  // con el tipo de letra seleccionado.
function dimensions($ldef, $texto)
{
  // Calcular el ancho
  $box=imagettfbbox ($ldef['size'], 0, $ldef['font'], $texto);
  $width = abs(abs($box[2]) - abs($box[0]));

  // Calcular el alto y la baseline
  $box=imagettfbbox ($ldef['size'], 0, $ldef['font'], 'ILyjgq'); // Tiene caracteres que no terminan en la baseline
  $height = abs($box[7] - $box[1]);
 
  $baseline = abs($box[5]);

  return array($width, $height, $baseline);
}

// Definimos un array con los posibles textos que vamos a presentar
$textArray=array("ejemplo", "de un fragmento de texto", 'gaspy@mi_servidor.com');


// Definimos el tipo de letra y el tamaño
$letra = array ('font'  => './LinLibertine_Bd.ttf',
        'size'  => 12,
        'color' => array(0,0,0),
        );

// Definimos el texto a presentar
$textID  = (isset($_GET['texto']))?$_GET['texto']:0;
$text = $textArray[$textID];

header('Content-Type: image/png');

// Creamos la imagen, calculando primero sus dimensiones dependiendo del tamaño del texto
$box_size=dimensions($letra, $text);
$im = imagecreatetruecolor($box_size[0], $box_size[1]);

// Creamos dos colores, y definimos el color que actuará como transparente
$background = imagecolorallocate($im, 255, 255, 255);
$fontColor  = imagecolorallocate($im, $letra['color'][0], $letra['color'][1], $letra['color'][2]);
imagecolortransparent($im, $background);

// Ponemos el fondo de la imagen transparente
imagefilledrectangle($im, 0, 0, $box_size[0], $box_size[1], $background);


// Creamos el texto
imagettftext($im, $letra['size'], 0, 0, $box_size[2], $fontColor, $letra['font'], $text);

// Generamos la salida
imagepng($im);
imagedestroy($im);
?>

Para el ejemplo he utilizado la fuente Linux Libertine Bold cuyo fichero ttf es LinLibertine_Bd.ttf, en realidad podemos utilizar cualquier fuente de la que dispongamos el fichero TTF.
El script que vemos, si lo llamamos desde el navegador con el parámetro textID=1 mostrará una imagen con el texto “de un fragmento de texto” dibujado dentro con el tipo de letra especificado anteriormente.

Ahora hacemos el siguiente archivo html:

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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Ejemplo de texto</title>
    <style text="text/css">
      <!--
     @font-face {
     font-family: "Linux Libertine";
     src: url(LinLibertine_Bd.ttf);
     }
     body{
     background: #eee;
     font: 12pt Linux Libertine,sans;
     }

     .texto{
     vertical-align:bottom;
     margin: 0;
     padding: 0;
     }
    -->
    </style>
    <meta name="author" content="Gaspar Fernández">
  </head>

  <body>
    <h1>Ejemplo de texto</h1>

    Esto es un ejemplo de inserción <img src="texto.php?textID=1" class="texto"/> incluyendo una imagen en PHP
   
    <hr>
    <address>
      <a href="http://totaki.com/poesiabinaria">Gaspar Fernández</a>,
    </address>
  </body>
</html>

Con la parte CSS:

1
2
3
4
@font-face {
     font-family: "Linux Libertine";
     src: url(LinLibertine_Bd.ttf);
     }

Estamos definiendo el fichero que se descargará para visualizar el tipo de letra, así nos aseguramos de que sea el mismo tipo de letra (el de la imagen y el de nuestro texto). El resultado debería ser algo parecido a esto:
textexample

Automatizando la publicación de nuestras páginas de Facebook

Lunes, 6 de Febrero de 2012 Gaspar Fernández Sin comentarios

facebook_1
Si administramos páginas de Facebook, en ocasiones nos interesa introducir contenidos procedentes de diversas fuentes, tal vez un RSS (o varios) (Por ejemplo, si administras la página de un blog, o quieres mostrar noticias), eso sí, de fuentes confiables. O tal vez quieres publicar un mensajes varias veces a lo largo de un día, o varios mensajes de forma escalonada en el tiempo.

Objetivos

El problema es que esto nos obliga a estar constantemente pendientes de esas publicaciones. En mi caso, cuando tengo tiempo, sí puedo entrar en mis páginas de Facebook para hacer publicaciones, pero me gustaría que esas publicaciones también fueran aprovechables para mis visitantes en Hispanoamérica, cuyos horarios son muy diferentes a los míos, así como para gente que suele conectar más por la mañana o por la tarde. Además, en ocasiones me interesa publicar varios mensajes en alguna de las páginas, pero quiero ver antes la reacción que tienen entre los usuarios (Comentarios y Me Gusta), sin ser demasiado pesado (cuando veo muchas publicaciones seguidas de una misma fuente me agobio y siento la tentación de dejar de recibir publicaciones de esa fuente).

Para solucionarlo, propongo montar una aplicación web (lo que muestro aquí es sólo un esbozo, ya que podemos hacerla tan compleja como queramos), para montar esta aplicación, aprovecharé información que ya he puesto en algún post anterior.

Mi objetivo es poder administrar todas mis páginas de Facebook desde un sitio centralizado, sin tener que entrar una a una modificando las publicaciones.

Base de datos de la aplicación

Como hemos visto en el post anterior, para publicar en nombre de una página, debemos almacenar los access tokens que dan permiso a la aplicación para publicar como si fuera esa página de Facebook. Además, debemos almacenar los IDs de páginas de Facebook para que la aplicación sepa quién va a publicar y dónde (en el muro de dicha página)

Para ello voy a utilizar el motor MySQL y así podremos subir la aplicación a cualquier hosting que soporte este motor. En la base de datos (facebook_autopublish), crearemos varias tablas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
CREATE TABLE `facebook_autopublish`.`paginas` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 128 ) NOT NULL ,
`access_token` VARCHAR( 255 ) NOT NULL ,
`category` VARCHAR( 64 ) NOT NULL ,
`fcbkId` VARCHAR( 32 ) NOT NULL ,
`last_update` BIGINT NOT NULL
) ENGINE = InnoDB;

ALTER TABLE `paginas` ADD INDEX ( `last_update` ) ;

CREATE TABLE `facebook_autopublish`.`publish` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`pageID` INT UNSIGNED NOT NULL ,
`time` BIGINT NOT NULL ,
`message` TEXT NOT NULL ,
PRIMARY KEY ( `id` ) ,
INDEX ( `id` )
) ENGINE = InnoDB;

ALTER TABLE publish ADD FOREIGN KEY ( pageID ) REFERENCES paginas( id ) ;

La tabla paginas contendrá lo siguiente:

  • id : identificador de la página para la aplicación que estamos desarrollando
  • name : nombre de la página, obtenido de Facebook
  • access_token : access_token de la página, obtenido de Facebook
  • category : categoría de la página, obtenida de Facebook
  • fcbkId : ID de la página en Facebook, nos servirá para saber dónde publicar
  • last_update : momento en el tiempo de nuestra última publicación en la página

La tabla publish contendrá lo siguiente:

  • id : Identificador de la publicación para la aplicación
  • pageID : Id de la página donde se va a publicar
  • time : Momento en el tiempo en que queremos publicar
  • message : Texto de la publicación

La primera tabla (paginas), se generará automáticamente al cargar la página de identificación en Facebook. Para la segunda tabla (publish), debemos crear un interfaz web o CLI que vaya introduciendo los mensajes que tenemos que ir publicando. Ese interfaz no lo voy a incluir en este ejemplo, podemos incluso hacerlo desde PHPMyAdmin, o desde el comando mysql.

Script de identificación

Este script contendrá la autorización de la aplicación, y el llenado de la tabla paginas con los datos extraídos de Facebook (los ID de página y los access_tokens son lo más importante), y tenemos que almacenarlos en base de datos, para ello podemos usar el siguiente script:

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<?php

$mysql_host = 'Host Mysql';
$mysql_user = 'Usuario MySQL';
$mysql_pass = 'Pass MySQL';
$mysql_db   = 'facebook_autopublish';

$api_key = 'API Key';
$api_sec = 'API Secret';

require_once('facebook_ext.php');
// Definimos constantes
define(NEEDED_PERMISSIONS,  'publish_stream,offline_access,manage_pages');
define('_scampo', '`');
define('_svalor', '\'');

// Definimos códigos de error
define(NOT_INSTALLED,      1);
define(NO_PERMISSIONS,     2);
define(NO_MYSQL_CONN,      3);
define(NO_PAGE_DATA,       4);
define(MALFORMED_ARRAY,   90);

// Funciones para el manejo de la bdd
function escapa($dato, $char, $numeric=true)
{
  if (($numeric) && (is_numeric($dato)))
    return ($dato+0);       /* Si es 0, no devolverá FALSE */
  else
    return $char.mysql_real_escape_string($dato).$char;
}

function valor($valor, $numeric=true)
{
  return escapa($valor, _svalor, $numeric);
}

function campo($valor, $numeric=true)
{
  return escapa($valor, _scampo, $numeric);
}

function insert($tabla, $datos)
{
  $uso='
INSERT';

  $sql=$uso.'
INTO '.campo($tabla). '(';
  $values='
VALUES (';

  $campos=array_keys($datos);
  $ndatos=count($campos);
 
  for ($i=0; $i<$ndatos; $i++)
    {
      $campo=$campos[$i];
      if ($i)
    {
      $sql.=", ";
      $values.=", ";
    }

      $valor = $datos[$campo];
      $sql.=campo($campo);
      $values.= valor($valor);
    }
  $values.=")";
  $sql.=") ".$values.";";

  $res = mysql_query($sql);
  // Depuración
  echo "Ejecutando: ".$sql.'
<br/>';
  return ($res)?mysql_insert_id():false; /* Devolver el ID del elemento insertado */
}

function truncate($table)
{
  return mysql_query("TRUNCATE TABLE ".campo($table));
}

try
{
  if (!mysql_connect($mysql_host, $mysql_user, $mysql_pass))
    throw new Exception('
No puedo conectar con el servidor MySQL', NO_MYSQL_CONN);

  // Generar otra excepción por si las moscas.
  mysql_select_db($mysql_db);

  $facebook = new FacebookExtended(array(  
                     '
appId'  => $api_key,
                     '
secret' => $api_sec,
                     '
cookie' => true ,
                       ));

 
  $sesion = $facebook->getUser();
  if (!$sesion)
    throw new Exception('
Aplicación no instalada', NOT_INSTALLED);

  echo "Estamos identificados en Facebook<br/>";
  echo "Usuario: ".$sesion."<br/>";

  $permissions = $facebook->askForPermissions(NEEDED_PERMISSIONS);
   
  if (!$permissions)
    throw new Exception('
No tengo permisos suficientes', NO_PERMISSIONS);
 
  $pagedata=$facebook->api('
/me/accounts');

  if ( (!$pagedata) || (!isset($pagedata['
data'])) || (count($pagedata['data'])==0) )
    throw new Exception('
No he recibido información de páginas', NO_PAGE_DATA);

  truncate('
paginas');

  $npages = count ($pagedata['
data']);
  for ($i=0; $i<$npages; $i++)
    {
      $pdata=$pagedata['
data'][$i];
      // Depuración
      echo "Insertando pagina: ".$pdata['
name']."<br/>";

      if (!insert('
paginas', array('name'         => $pdata['name'],
                   '
access_token' => $pdata['access_token'],
                   '
category'     => $pdata['category'],
                   '
fcbkId'       => $pdata['id'],
                   '
last_update'  => 0)) )
    echo mysql_error()."<br/>";
    }

}
catch (FacebookException $e)
{
  echo "Error de Facebook: ".$e->getCode().": ".$e->getMessage();
}
catch (Exception $e)
{
  switch ($e->getCode())
    {
    case NOT_INSTALLED:
      $facebook->loginUser();
      break;
    case NO_PERMISSIONS:
      $facebook->loginUser(NEEDED_PERMISSIONS);
      break;

    default:
      echo "Ocurrió un error: ".$e->getMessage();
    }
}
?>

Publicando mensajes automáticamente

Ahora, sólo tenemos que ir insertando entradas dentro de la tabla publish, especificando el momento en el que se va a insertar en el campo time y el ID de la página donde se va a insertar (ID dentro de la aplicación, no dentro de Facebook, se puede mirar en la tabla paginas)

Asimismo la aplicación buscará mensajes nuevos para publicar y que no haga menos de dos horas (configurable) desde el último mensaje publicado en la página especificada. Para ello tenemos el siguiente código (publica.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
<?php

$mysql_host = 'MySQL Host';
$mysql_user = 'MySQL User';
$mysql_pass = 'Password';
$mysql_db   = 'facebook_autopublish';

$api_key = 'xxxxxxxxxxxx';
$api_sec = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

require_once('facebook_ext.php');

// Definimos constantes
// Tiempo mínimo entre publicaciones, 7200 segundos = 2h
define(MIN_TIME_BET_PUB,   7200);

// Definimos códigos de error
define(NOT_INSTALLED,      1);
define(NO_PERMISSIONS,     2);
define(MALFORMED_ARRAY,   90);
define(BAD_MYSQL,          3);

try
{
  if (!mysql_connect($mysql_host, $mysql_user, $mysql_pass))
    throw new Exception('No puedo conectar con el servidor MySQL', NO_MYSQL_CONN);

  // Generar otra excepción por si las moscas.
  mysql_select_db($mysql_db);
 
  $campos='paginas.id as pID, publish.id as pubId, paginas.fcbkId, paginas.access_token, publish.message';

  $sql='SELECT '.$campos.' FROM `publish` LEFT JOIN `paginas` ON publish.pageID=paginas.id WHERE last_update<'.(time()-MIN_TIME_BET_PUB).' ORDER BY last_update ASC LIMIT 1';
  $res=mysql_query($sql);
  if (!$res)
    throw new Exception('Hubo un error en la sentencia MySQL ('.$sql.'): '.mysql_error(), BAD_MYSQL);

  // Si se ha devuelto algo...
  if (mysql_num_rows($res)>0)
    {
      $data = mysql_fetch_assoc($res);

      $facebook = new FacebookExtended(array(  
                         'appId'  => $api_key,
                         'secret' => $api_sec,
                         'cookie' => true ,
                           ));

      $destino=$data['fcbkId'];
      $access_token=$data['access_token'];
      $public=$data['message'];

      print_r( $facebook->api('/'.$destino.'/feed', 'post', array('access_token' => $access_token,
                                  // 'uid' => $destino,
                                  'message' => $public)));  

      $sql = 'UPDATE paginas SET last_update='.time().' WHERE id=1';
      mysql_query($sql);

    }
} catch (Exception $e)
{
  echo "Ocurrió un error: ".$e->getMessage();
}
?>

Ejecutándolo en el tiempo

El objetivo de estos scripts es poder ejecutarlos cada cierto tiempo y, si usamos un sistema UNIX podemos hacer que cada cierto tiempo (cada 2h, por ejemplo), se haga una petición a la página, para ver si tenemos mensajes nuevos pendientes de publicación, y si hay, que los publique (publica.php ya se encarga de eso).

Para añadir el programa en nuestro cron, debemos ejecutar en un terminal:

$ crontab -e

Y allí escribir lo siguiente:

15 */2 * * * wget http://dominio.xxx/carpeta/publica.php

Donde cambiamos la dirección especificada por la dirección donde hemos instalado el script publica.php. Esto hará que se ejecute cada 2h en el minuto 15, todos los días, todos los meses y todos los días de la semana.

Consideraciones de seguridad

Es una buena idea hacer que index.php sólo podamos ejecutarlo nosotros desde nuestra sesión de Facebook, restringiendo la ejecución a nuestro ID de usuario. Así evitamos que la base de datos se pueble con páginas que no queremos, y también estaría bien restringir esa página con contraseña desde Apache, así evitamos sorpresas.

También es conveniente no hacer TRUNCATE TABLE todo el rato, sino ver y comprobar que los access_tokens no cambian (lo dejamos así, porque en ocasiones, Facebook los ha cambiado, reiniciado, o éstos han caducado pasados unos meses).

En la parte de publica.php sería conveniente el envío de una contraseña, para que no pueda publicar cualquiera, ya sea en una petición POST, GET, o enviándola por SSL. Así evitamos que cualquiera ejecute publica.php , sólo nosotros.

Publicando en Facebook como página para mantener a nuestros fans

Lunes, 30 de Enero de 2012 Gaspar Fernández Sin comentarios

poesiabinaria

Si administras una página de Facebook, esto te interesa, ya que puedes gestionar las publicaciones de forma automática, por ejemplo, si tienes muchas cosas que publicar y quieres hacerlo de manera escalonada, para no hacerlo todo seguido y mantener alerta a tus seguidores.

Para poder poner en práctica todo esto, te recomiendo leer estos artículos anteriores:

Estudiando el tema

El problema de administrar páginas, es que tienes que estar identificado como estas, y además, hacerlo en modo offline. Por otra parte, las páginas tienen sus administradores y éstos son los usuarios que se pueden identificar en aplicaciones.
Facebook hace todo esto a través de palabras de acceso (access tokens), cuando un usuario se identifica en una aplicación se genera un token único para ese usuario y éste durará un tiempo, durante ese tiempo, la aplicación podrá realizar las acciones que el usuario le ha dado permiso para hacer.

En el caso de las páginas, debemos generar un access token que valga para la página en cuestión que queremos manejar. Ese access token debemos pasárselo a la llamada a la API para publicar.

Obteniendo los access tokens de las páginas que administro

Para ello hay que hacer la llamada a la API /me/accounts, con lo que obtendremos un listado completo de las páginas que administramos, ID de páginas (para poder realizar las publicaciones) y los access tokens necesarios para publicar en nombre de esas páginas.

Podemos modificar el programa que teníamos para identificarnos (index.php) de la siguiente manera (facebook_ext está para descarga en un post anterior):

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
<?php

$api_key = 'xxxxxxxxxxx';
$api_sec = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

require_once('facebook_ext.php');
// Definimos constantes
define(NEEDED_PERMISSIONS,  'publish_stream,offline_access,manage_pages');

// Definimos códigos de error
define(NOT_INSTALLED,      1);
define(NO_PERMISSIONS,     2);

$facebook = new FacebookExtended(array(  
                       'appId'  => $api_key,
                       'secret' => $api_sec,
                       'cookie' => true ,
                     ));

try
{
 
  $sesion = $facebook->getUser();
  if (!$sesion)
    throw new Exception('Aplicación no instalada', NOT_INSTALLED);

  echo "Estamos identificados en Facebook<br/>";
  echo "Usuario: ".$sesion."<br/>";

  $permissions = $facebook->askForPermissions(NEEDED_PERMISSIONS);
   
  if (!$permissions)
    throw new Exception('No tengo permisos suficientes', NO_PERMISSIONS);
 
  print_r($facebook->api('/me/accounts'));
}
catch (FacebookException $e)
{
  echo "Error de Facebook: ".$e->getCode().": ".$e->getMessage();
}
catch (Exception $e)
{
  switch ($e->getCode())
    {
    case NOT_INSTALLED:
      $facebook->loginUser();
      break;
    case NO_PERMISSIONS:
      $facebook->loginUser(NEEDED_PERMISSIONS);
      break;

    case MALFORMED_ARRAY:
      echo $e->getMessage();
      break;

    default:
      echo "Ocurrió un error no identificado";
    }
}
?>

Con este código, pediremos permiso para administrar páginas, para uso offline y para publicar mensajes en nombre del usuario. Cuando estemos identificados, nos devolverá un array con los nombres de las páginas, los ID y los access tokens. El array dentrá la siguiente forma:

Array
(
[data] => Array
(
[0] => Array
(
[name] => Nombre de página 1
[access_token] => xxxxxxx
[category] => Website
[id] => 123456789
)

[1] => Array
(
[name] => Nombre de página 2
[access_token] => xxxxxxx2
[category] => Website
[id] => 987654321
)
………………..
[n] => Array
(
[name] => Nombre de página N
[access_token] => xxxxxxxn
[category] => Website
[id] => 918273645
)
)
)

Se mostrarán todas las páginas que administramos. Ahora tendremos que anotar el ID de la página con la que queremos publicar y el access token para copiarlos en el código del programa encargado de publicar.

Publicando como si fuéramos una página de Facebook

Para hacer la publicación tenemos que hacer una llamada a /ID_de_página/feed especificando el access token con el que queremos publicar:

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
<?php

$api_key = 'xxxxxxxxxxx';
$api_sec = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

require_once('facebook_ext.php');

$facebook = new FacebookExtended(array(  
                       'appId'  => $api_key,
                       'secret' => $api_sec,
                       'cookie' => true ,
                     ));

try
{
  // ID de la página que queremos editar. La podemos ver en la URL de Facebook de la página
  $destino=189639191053576;
  $access_token='XXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
  $public='Probando mensajes automáticos con el modo offline';

  print_r( $facebook->api('/'.$destino.'/feed', 'post', array('access_token' => $access_token,
                                  'message' => $public)));  
} catch (Exception $e)
{
  echo "Ocurrió un error";
}
?>

Facil, ¿no? Si trabajamos un poco con todo esto podemos conseguir automatizar los mensajes que se van a publicar en Facebook desde las páginas que gestionamos.

Escribiendo en muros desde nuestra aplicación de Facebook

Domingo, 22 de Enero de 2012 Gaspar Fernández 9 comentarios

fb_website3 Uno de los usos más extendidos de las aplicaciones de Facebook es el de escribir en el propio muro o en el muro de nuestros amigos. Vamos a hacer un ejemplo de esto utilizando la Graph API de Facebook, a través de la biblioteca oficial que ellos nos dejan en GitHub. Para empezar a crear la aplicación os recomiendo leer este post anterior donde se dice paso a paso cómo se debe crear y cómo empezar a escribir código.

Pedir permiso para publicar

Antes de nada, debemos pedir permiso para publicar en el muro del usuario, para pedir permiso, lo podemos hacer en el mismo momento que ejecutamos el método getLoginUrl() pasando como parámetro un array cuyo único elemento será ’scope’ y su valor serán los permisos requeridos separados por comas. Por ejemplo:

1
$facebook->getLoginUrl(array('scope' => 'publish_stream'));

El permiso que debemos pedir para poder publicar en los muros de Facebook es stream_publish. Por otra parte, puede que ya hayamos identificado la aplicación con anterioridad, por lo que al estar dentro del sistema no hacemos llamada a getLoginUrl(), para ello debemos comprobar los permisos de que disponemos y eso lo hacemos con una llamada a la API a /usuario/permissions:

1
print_r($facebook->api('/me/permissions'));

Lo que nos devolverá un array con los permisos que dispone la aplicación, el array tendrá un elemento ['data'] que será otro array, cuyo elemento [0] contendrá otro array con los permisos:

Array ( [data] => Array ( [0] => Array ( [installed] => 1, [publish_stream] =>1 ) ) )

fb_website2

Publicar un mensaje en mi muro

Para publicar un mensaje en mi muro, debemos hacer una llamada a /usuario/feed y enviar por post la información referente al mensaje deseado:

1
$facebook->api('/me/feed', 'post', array('message' => $mensaje));

Código fuente demo

En este código fuente, he integrado excepciones para controlar los posibles errores (No identificado, No tengo permisos, Facebook me ha devuelto un array incorrecto), en este caso, los errores de identificación son salvables, pero los demás no. Para probar este código, debes cambiar la $api_key y la $api_sec:

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
<?php

$api_key = 'xxxxxxxxxxxxx';
$api_sec = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

require_once('facebook.php');

// Definimos códigos de error
define(NOT_INSTALLED,      1);
define(NO_PUBLISH_STREAM,  2);
define(MALFORMED_ARRAY,   90);

$facebook = new Facebook(array(  
                   'appId'  => $api_key,
                   'secret' => $api_sec,
                   'cookie' => true ,
                 ));

try
{
 
  $sesion = $facebook->getUser();
  if (!$sesion)
    throw new Exception('Aplicación no instalada', NOT_INSTALLED);

  echo "Estamos identificados en Facebook<br/>";
  echo "Usuario: ".$sesion."<br/>";

  // Obtenemos los permisos del usuario
  $permissions = $facebook->api('/'.$sesion.'/permissions');
  if (!isset($permissions['data'][0]))
    throw new Exception('Facebook ha devuelto un array mal formado', MALFORMED_ARRAY);

  if (!isset($permissions['data'][0]['publish_stream']))
    throw new Exception('No tengo permiso publish_stream', NO_PUBLISH_STREAM);

  $mensaje='Probando la publicación de mensajes en Facebook...';
  print_r( $facebook->api('/189639191053576/feed', 'post', array('message' => $mensaje)));

} catch (Exception $e)
{
  switch ($e->getCode())
    {
    case NOT_INSTALLED:
      $login_url = $facebook->getLoginUrl();
      header('Location: '.$login_url);
      die();
      break;
    case NO_PUBLISH_STREAM:
      $login_url = $facebook->getLoginUrl(array('scope'=>'publish_stream'));
      header('Location: '.$login_url);
      die();
      break;

    case MALFORMED_ARRAY:
      echo $e->getMessage();
      break;

    default:
      echo "Ocurrió un error no identificado";
    }
}
?>

Publicando en otros muros y páginas

Para publicar en el muro de otros usuarios, simplemente tenemos que sustituir la dirección de la llamada a la API donde publicamos de /me/feed a /usuario/feed donde usuario es el texto que aparece al acceder en la dirección de la página principal de Facebook de alguno de nuestros amigos (también puede ser su ID de usuario, pero ya es difícil de obtener).

Para publicar en páginas debemos sustituir el /usuario/feed por /id_de_pagina/feed donde el ID de la página es el número que aparece en la dirección de la página en cuestión, si por ejemplo, la URL de la página de Facebook de este blog es:https://www.facebook.com/pages/Poesía-Binaria/189639191053576 ; la id de la página es la que está en negrita.

Sólo teniendo el permiso publish_stream ya podemos publicar con el nombre de usuario que tenemos actualmente en cualquier lado dentro de Facebook.

Linux en Alias

Jueves, 19 de Enero de 2012 Gaspar Fernández Sin comentarios

alias_kdeEn la serie Alias, en el episodio 11 de la segunda temporada “Un Escalón Más Alto”, o “A Higher Echelon”, podemos ver este fotograma (casi en el minuto 17), en el que vemos un escritorio KDE y una terminal abierta.

Por otra parte, a lo largo del capítulo, se pueden ver varias pantallas como esta, en las que de fondo, si entornamos un poco los ojos, se está compilando con cc y con un argumento: “-D_GNU_SOURCE

alias_kde2

Fuente: http://groups.google.com/group/comp.windows.x.kde/msg/3100d0f3062fac2a

Visita otras webs de la red