Publi

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

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.

También podría interesarte...

There are 2 comments left Ir a comentario

  1. Pingback: Bitacoras.com /

  2. Pingback: BlogESfera.com /

Leave a Reply