Archivo

Entradas Etiquetadas ‘MySQL’

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.

Instalar y configurar un servidor LAMP

Lunes, 17 de Octubre de 2011 Gaspar Fernández Sin comentarios

Lámpara de bajo consumoEn esta ocasión el servidor LAMP a instalar corresponderá con Linux + Apache + MySQL + PHP, intentaré dejarlo todo funcionando.

Éste es el servidor local que suelo utilizar para mis proyectos web, de todas formas no me quiero meter en necesidades muy avanzadas, ni de seguridad (es un servidor local para hacer pruebas, desarrollar webs, y correr servicios locales; no un servidor de producción), si el servidor está cerrado al exterior, mejor. Esta guía dejará el servidor operativo, lo que hagamos con él, es cosa nuestra.

En este tutorial tocaré los siguientes puntos:

Instalación de software

En este punto, supongo que tenéis una máquina GNU/Linux instalada, si necesitas ayuda para instalar una distribución, puedes probar con este enlace.
Esta parte, será especial para los derivados de Debian o Ubuntu, ya que el nombre de los paquetes es especial para dicha distribución. Lo instalamos desde terminal:

$ sudo apt-get install libapache2-mod-php5 php5-gd libgd-tools php5-curl php5-mcrypt php-pear mysql-server php-mysql

Con esto se instalarán más paquetes y dependencias que serán necesarios para nuestro servidor, además, cuando se esté instalando el servidor MySQL nos preguntará qué contraseña queremos para root:
Root MySQL
No tiene que ser la misma que root de nuestro sistema, será una clave para controlar todas las bases de datos del servidor.

apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1 for ServerName

Si nada más instalar tu servidor web dice esto, pasar no pasa nada, pero molesta un poco que de un fallo, para ello tenemos que editar /etc/apache2/httpd.conf y escribir lo siguiente:

ServerName localhost

Reiniciamos el servidor y ya está todo correcto:

$ sudo service apache2 restart

Creando el directorio de trabajo

Yo utilizo esto para tener las webs alojadas en /home, ya que lo tengo montado en la partición más grande de mi disco duro. Aquí tenemos varias opciones:

  • En el directorio personal de nuestro usuario principal (es rápido y no está mal si sólo nosotros usamos el ordenador). Por ejemplo /home/usuario/proyectos/www/
  • Crear un directorio en /home; por ejemplo /home/servidor/www/
    • Tras ello, debemos darle privilegios de escritura al usuario con el que vamos a trabajar.
    • O por el contrario, si trabajarán varios usuarios, podemos crear un grupo (por ejemplo, desarrolloweb), dar privilegios de escritura al grupo y añadir todos los usuarios a ese grupo.

      $ sudo groupadd desarrolloweb
      $ sudo mkdir -p /home/servidor/www
      $ sudo chgrp -R desarrolloweb /home/servidor/www
      $ sudo gpasswd -M usuario1,usuario2,usuario3,…,usuarioN desarrolloweb

  • Crear un usuario (desarrolloweb) y un grupo (desarrolloweb) y dar privilegios a los usuarios que vayan a acceder como en el apartado anterior.
  • Utilizar el mismo usuario con el que se ejecuta apache (apache, httpd, www-data, depende del sistema, podemos mirar el archivo /etc/passwd para ver todos los usuarios). Para ese usuario crear un directorio en /home, asignar el grupo a desarrolloweb e introducir usuarios en ese grupo:

    $ sudo mkdir -p /home/servidor/www/
    $ sudo usermod -d /home/servidor/
    $ sudo chown -R www-data:desarrolloweb /home/servidor
    $ sudo gpasswd -M usuario1,usuario2,usuario3,…,usuarioN desarrolloweb

    Este último método puede sernos útil cuando nuestros scripts escriban en archivos dentro de nuestro árbol, siempre que esos directorios tengan a www-data como usuario

  • Normalmente, nuestra instalación de apache creará también un grupo llamado www-data (o apache, o httpd, etc), por lo que podemos añadir a todos los usuarios, en lugar de a desarrolloweb a www-data.
  • Se nos pueden ocurrir muchas más formas de organizarnos.

Nota: si optamos por alguna configuración de grupo, tenemos que dar permisos 775 a los directorios del servidor. Y cuando queramos que algún archivo sea modificado/creado por el servidor web debemos darle permiso al este servidor. Si los usuarios que pueden acceder pertenecen al mismo grupo que el servidor web (recordad, www-data, httpd, apache…) con dar permiso al grupo basta, si no, tendremos que modificar los permisos del fichero para permitir a otros la escritura (chmod o+w archivo). Ahora un truco, cuando estemos creando archivos desde terminal, con un usuario perteneciente a desarrolloweb podemos hacer lo siguiente:

$ newgrp desarrolloweb
$ umask 0002

Con esto conseguimos que todos los ficheros que creemos en la sesión pertenezcan al grupo desarrolloweb y tengan los permisos 664 (lectura y escritura para propietario y grupo y lectura para otros) y los directorios, 775 (lectura, escritura y ejecución (o entrada) para propietario y grupo, lectura y entrada para otros).

Una vez tenemos el directorio de trabajo creado, podemos crear enlaces a el dentro de los directorios personales de los usuarios que van a trabajar para que tengan un acceso más rápido, por ejemplo, para mi usuario, crearé un enlace a /home/gaspy/proyectos/www:

$ ln -s /home/servidorweb/www /home/gaspy/proyectos/www

Cambiando el directorio de trabajo en el servidor web

Una vez tenemos nuestro directorio de trabajo, tenemos que decirle a Apache que lo use, por defecto utilizará /var/www ; queremos utilizar nuestro directorio de trabajo. Los valores por defecto no los tocaremos, por si algún día queremos utilizarlos como plantilla ( y por si alguna actualización los re-escribe). El método que muestro es más o menos general, aunque tal vez dependiendo de la distribución varíe algún nombre de archivo:

$ cd /etc/apache2
$ sudo a2dissite 000-default

La utilidad a2dissite elimina el enlace 000-default (dentro de /etc/apache2/sites-enabled/) a sites-available/default, por lo que copiaremos ese último y crearemos otro enlace en sites-enabled para que sea nuestro sitio principal (ayudándonos de la utilidad a2ensite). Tanto a2dissite como a2ensite son dos scripts que nos facilitan un poco la vida a la hora de manejar esos enlaces.

$ sudo cp sites-available/default sites-available/trabajo
$ sudo a2ensite trabajo
$ sudo nano sites-available/trabajo

Ahora debemos modificar algunas líneas de ese documento relativas a la ruta de trabajo, sustituyendo donde ponga /var/www por /home/servidorweb/www dejándolas así:

DocumentRoot /home/servidorweb/www
<Directory /home/servidorweb/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>

Aunque más adelante modificaremos alguna línea más en este archivo (podemos hacerlo todo seguido, pero para este artículo prefiero indicarlo paso a paso), salvamos y salimos (en nano, Control-X).

Probando el servidor

Vamos a introducir un archivo index.php en /home/servidorweb/www/ para que se vea cuando accedemos al raíz de nuestro servidor. Sólo por hacer la prueba, puedes saltar este paso si quieres. El archivo contendrá (debéis sustituir UTF-8 por la codificación con la que creéis el archivo, y la zona horaria Europe/Madrid por la zona horaria donde estéis):

1
2
3
4
5
<?php
   date_default_timezone_set('Europe/Madrid');
   echo "<h1>Funciona!</h1>";
   echo '<p>'.htmlentities('El servidor está funcionando. Son las: '.date('H:i').' del día '.date('d/m/Y'), ENT_COMPAT, 'UTF-8').'</p>';
?>

Para ver el resultado, si estáis en el mismo ordenador donde habéis instalado el servidor, acceded a http://localhost/ , si no, acceded a través de la IP de la máquina servidor, debería dar un mensaje como este:
Server funcionando

Permitir cambiar las opciones de directorios con .htaccess

Es muy útil si vamos a utilizar mod_rewrite, contraseñas en directorios o modificar filtros, documentos de error, etc. aunque por defecto viene deshabilitada cualquier configuración que podamos hacer desde aquí. Para ello, debemos abrir el mismo archivo de antes /etc/apache2/sites-available/trabajo para edición (igual que antes, y cambiar la directiva AllowOverride de None a All (dentro de Directory /home/servidorweb/www), al final se quedaría así:

<Directory /home/servidorweb/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Directory>

Seguramente haya otra etiqueta <Directory>, en este caso ““, con otra directiva AllowOverride que podemos dejar a None, esto es para cuando haya un archivo .htaccess en un nivel superior a nuestro directorio de trabajo, por ejemplo en /home/servidorweb; si ponemos la directiva a “All”, sí que se procesará ese archivo, aunque en este caso, si va a ser una configuración común a todo el servidor (ya que afectará a todos los subdirectorios que tengamos exportados) podemos ponerla en /etc/apache2/sites-available/trabajo.

Configurar mod-rewrite

$ sudo a2enmod rewrite

Ejecuta un script que habilita el módulo especificado. Para ver un listado de los módulos especificados podemos mirar en el directorio /etc/apache2/mods-available ; este script hará un enlace de un módulo en /etc/apache2/mods-enabled. Desde aquí podemos activar el módulo que queramos. Para desactivar ejecutamos como root a2dismod. De forma muy parecida a como hicimos con el sitio web.

Instalamos phpmyadmin

Podemos instalarlo automáticamente con nuestra distribución, por ejemplo en Debian/Ubuntu y derivados:

$ sudo apt-get install phpmyadmin

Nos pedirá la contraseña de la base de datos y listo.

Personalmente, no me gusta que mi distribución haga ciertos cambios y este es uno de ellos, me gusta hacer la instalación de phpMyAdmin de forma manual, así como la de ciertos scripts y utilidades del servidor… en ocasiones edito algún archivo de configuración por nfs y tengo un acceso directo a ellos, además, me gusta complicarme un poco la vida :)

Lo primero es descargarlo, de la web oficial. La última versión hoy es la 3.4.5 (bonito número) por tanto lo instalaremos. Primero creo un directorio para las utilidades de mi servidor local, y tras ello descomprimo ahí phpmyadmin; el archivo comprimido de phpMyAdmin se encuentra en /home/servidorweb/targz:

$ cd /home/servidorweb
$ mkdir util
$ cd util
$ tar xvzf ../targz/phpMyAdmin-3.4.5-all-languages.tar.gz

Se descomprimirá todo en el directorio phpMyAdmin-3.4.5-all-languages/ que renombraremos a pma (PhpMyAdmin), aunque el nombre es lo de menos, sólo queremos un acceso fácil:

$ mv phpMyAdmin-3.4.5-all-languages pma

A continuación vamos a dar acceso al servidor web al directorio /home/servidorweb/util/ ya que está fuera de /home/servidorweb/www/ que es el que tiene acceso desde web. Para ello creamos un nuevo archivo en /etc/apache2/conf.d/ llamado, por ejemplo utilidades.conf, y contendrá lo siguiente:

Alias /util/ “/home/servidorweb/util/”

<Directory “/home/servidorweb/util”>
AllowOverride None
Order allow,deny
Allow from all
</Directory>

Para ver los cambios recargamos la configuración del servidor:

$ sudo service apache2 reload

En este punto, si accedemos desde el navegador a nuestro servidor en la ruta donde hemos vinculado phpmyadmin, por ejemplo http://localhost/util/pma/ veremos:
pma
Ya tenemos phpMyAdmin funcionando, aunque falta un pequeño detalle (no nos impide en cierto modo trabajar, pero ya que lo instalamos lo instalamos bien). phpMyAdmin tiene funciones avanzadas como la creación de PDFs, diseñador de bases de datos, historial y algunas cosas más y para ello necesita que creemos una base de datos e instalemos algunas tablas en ella, para ello, primero crearemos el usuario pma en nuestra base de datos, lo haremos desde el comando mysql:

$ mysql -u root -p

Enter password: [introducimos la contraseña, la primera que introdujimos al principio del tutorial]
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 104

mysql> CREATE USER ‘pma’@'localhost’ IDENTIFIED BY ‘axK12jMf’
Query OK, 0 rows affected (0.03 sec)
mysql> exit

La contraseña podemos generarla con pwgen, cuando terminemos de configurar esto, no la necesitaremos para nada.
Ahora cargamos en la base de datos las tablas de phpMyAdmin (las encontramos dentro del directorio de instalación):

$ mysql -u root -p < /home/servidorweb/util/pma/scripts/create-tables.sql

Ahora damos privilegios al usuario pma para la base de datos phpmyadmin:

$ mysql -u root -p
mysql> GRANT SELECT, INSERT, DELETE, UPDATE ON `phpmyadmin`.* TO ‘pma’@'localhost’;
mysql> exit

Para terminar de configurar debemos crear el fichero config.inc.php, aunque phpMyAdmin trae un fichero llamado config.sample.inc.php que nos puede servir de plantilla. Para ello:

$ cd /home/servidorweb/util/pma/
$ cp config.sample.inc.php config.inc.php

Y editamos el archivo. Podemos ir a http://localhost/util/pma/setup/ y hacer algunos ajustes, luego podemos copiar el archivo generado en config.inc.php o, de manera manual, editando el archivo, para ello, lo primero que debemos rellenar es la línea de blowfish_secret, será una frase secreta para la autentificación de tipo cookie de la aplicación; podemos poner una frase cualquiera, lo primero que se nos ocurra, el caso es que sea secreto, podemos generarlo si queremos con:

$ pwgen -yns 46 1

El tema es que se quede algo como:

1
$cfg['blowfish_secret'] = 'Frase secreta que me acabo de inventar'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */

Ahora, debemos rellenar las opciones del servidor MySQL, para ello (podemos copiar y pegar, aunque viene comentado en el archivo):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$cfg['Servers'][$i]['controluser'] = 'pma';
$cfg['Servers'][$i]['controlpass'] = 'CLAVE PMA';

/* Storage database and tables */
$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
$cfg['Servers'][$i]['bookmarktable'] = 'pma_bookmark';
$cfg['Servers'][$i]['relation'] = 'pma_relation';
$cfg['Servers'][$i]['table_info'] = 'pma_table_info';
$cfg['Servers'][$i]['table_coords'] = 'pma_table_coords';
$cfg['Servers'][$i]['pdf_pages'] = 'pma_pdf_pages';
$cfg['Servers'][$i]['column_info'] = 'pma_column_info';
$cfg['Servers'][$i]['history'] = 'pma_history';
$cfg['Servers'][$i]['tracking'] = 'pma_tracking';
$cfg['Servers'][$i]['designer_coords'] = 'pma_designer_coords';
$cfg['Servers'][$i]['userconfig'] = 'pma_userconfig';

Arriba del todo, en la segunda línea, debemos cambiar el valor por la clave que le asignamos al usuario pma.
Por otra parte, si utilizamos la base de datos adicional (phpmyadmin), necesitamos utilizar la extensión mysqli de php en lugar de mysql (puede haber problemas si no lo hacemos):

1
2
/* Select mysqli if your server has it */
$cfg['Servers'][$i]['extension'] = 'mysqli';

Si queremos, podemos incluir servidores a la lista de autentificación inicial de phpMyAdmin, con lo que podremos acceder sin contraseña a nuestro servidor (como root o como el usuario que elijamos), puede ser un método un tanto inseguro, pero si sólo estamos nosotros y tenemos el servidor cerrado al exterior no hay problema. Para ello, debajo de la identificación del primer servidor (las líneas que hemos añadido), añadimos lo siguiente en config.inc.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
$i++;
$cfg['Servers'][$i]['verbose'] = 'Servidor Local';
$cfg['Servers'][$i]['host'] = 'localhost';
$cfg['Servers'][$i]['port'] = '';
$cfg['Servers'][$i]['socket'] = '';
$cfg['Servers'][$i]['connect_type'] = 'tcp';
$cfg['Servers'][$i]['extension'] = 'mysqli';
$cfg['Servers'][$i]['auth_type'] = 'config';
$cfg['Servers'][$i]['user'] = 'root';
$cfg['Servers'][$i]['password'] = 'NUESTRA CLAVE DE ROOT DE MYSQL';
$cfg['Servers'][$i]['controluser'] = 'pma';
$cfg['Servers'][$i]['controlpass'] = 'CLAVE PMA';
/* Ponemos esto de nuevo */
/* Storage database and tables */
$cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
$cfg['Servers'][$i]['bookmarktable'] = 'pma_bookmark';
$cfg['Servers'][$i]['relation'] = 'pma_relation';
$cfg['Servers'][$i]['table_info'] = 'pma_table_info';
$cfg['Servers'][$i]['table_coords'] = 'pma_table_coords';
$cfg['Servers'][$i]['pdf_pages'] = 'pma_pdf_pages';
$cfg['Servers'][$i]['column_info'] = 'pma_column_info';
$cfg['Servers'][$i]['history'] = 'pma_history';
$cfg['Servers'][$i]['tracking'] = 'pma_tracking';
$cfg['Servers'][$i]['designer_coords'] = 'pma_designer_coords';
$cfg['Servers'][$i]['userconfig'] = 'pma_userconfig';

Exportar desde MySQL a CSV

Jueves, 3 de Febrero de 2011 Gaspar Fernández 3 comentarios

Hace tiempo leí en los foros de MySQL una chuleta interesante. La copié en una página de keepnote hasta ahora. Es para hacer una petición que escriba su salida en un archivo en formato CSV directamente.

Para ello, la petición debe tener esta forma:

1
2
3
4
SELECT campos INTO OUTFILE '/ruta/archvo.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM tabla;

Donde campos son los campos que vas a pedir, por ejemplo * para pedir todos; /ruta/archivo.csv es el archivo que se creará y tabla es la tabla a consultar en cuestión. Eso sí, no sólo vale para una tabla, podemos hacer peticiones todo lo complicadas que queramos y guardarlas en CSV.

Precaución, el usuario mysql (o el usuario con el que se ejecuta mysql debe tener permisos de creación en el directorio seleccionado); el archivo NO puede existir, esto es una medida de precaución para que no nos podamos cargar nada al crear archivos con MySQL; y, por último, tenemos que tener el permiso FILE en el usuario de mysql con el que estemos haciendo la consulta, para ello podemos, desde root, hacer lo siguiente:

1
GRANT FILE ON *  . *  TO 'usuario'@'host' ;

Como aclaración, debo recalcar que el permiso FILE es para usuarios de MySQL no de nuestro sistema; y el query anterior debe ser lanzado como root de MySQL.

Restablecer contraseña de root en servidor MySQL

Miércoles, 8 de Diciembre de 2010 Gaspar Fernández Sin comentarios

En ocasiones, sobre todo en nuestro servidor de pruebas (que a lo mejor puede ser
nuestro servidor de producción), podemos perder la contraseña de root de MySQL, y es un
fastidio, porque se nos puede pasar por la cabeza reconfigurar el paquete y perderlo
todo, pero son momentos en los que hay que tener paciencia y si tenemos información, no
es plan de destruir gratuitamente los datos.

Para ello, dejo unos sencillos pasos con los que restableceremos la contraseña de root
de MySQL (es necesario tener privilegios en el ordenador en el que está instalado
MySQL):

1. Primero detenemos el servicio MySQL, aquí dejo tres formas dependiendo de la
distribución:

1.1. $ service mysqld stop
1.2. $ /etc/init.d/mysqld stop
1.3. $ /etc/rc.d/mysqld stop

2. Tras ello, con privilegios de root, arrancamos MySQL de un modo especial, ignorando
las tablas de privilegios.

root $ mysqld –skip-grant-tables

Dependiendo de la versión de MySQL, puede que no nos deje arrancar el demonio como
usuario root, por lo que le daremos un nombre de usuario (este será el usuario con el
que arrancará mysql)

root $ mysqld -u mysql –skip-grant-tables &

En la mayoría de los sistemas el usuario será mysql.

3. Accedemos al servicio como superusuario (ya que no se comprueban las tablas de
privilegios, tenemos acceso). Esto lo podemos hacer como usuario normal. Accederemos
también a la base de datos llamada mysql (donde estan las tablas de privilegios)

$ mysql -u root mysql &

4. Desde mysql establecemos la nueva contraseña:

mysql> UPDATE mysql.user SET Password=PASSWORD(’nueva_contraseña’) WHERE
User=’root’;
mysql> FLUSH PRIVILEGES;

5. Salimos

mysql> quit

6. Cerramos mysqld (como root), tardará unos segundos, debemos ser pacientes

$ killall mysqld

7. Iniciamos el servidor MySQL normalmente, del mismo modo que lo paramos en el paso 1:

7.1. $ service mysqld start
7.2. $ /etc/init.d/mysqld start
7.3. $ /etc/rc.d/mysqld start

Ya debemos poder trabajar normalmente con nuestra nueva contraseña.

Pecados capitales: ORDER BY RAND() cuando sólo queremos una fila

Martes, 8 de Diciembre de 2009 Gaspar Fernández 1 comentario

Cometí el error cuando estrené las aplicaciones de frases en Facebook de utilizar la siguiente sentencia SQL para sacar una frase aleatoria:

1
SELECT * FROM `frases` ORDER BY RAND() LIMIT 1;

Al principio funcionaba bien, la verdad es que no confiaba mucho en el crecimiento de la aplicación, por lo que dejé el código así. Pero al cabo de unos días, noté que mi proveedor de hosting desactivó mi cuenta por excesivo uso de CPU: el rápido crecimiento de usuarios y frases dentro de la aplicación causaron un uso exponencial de CPU en mi servidor.
Al principio no parece lógico pero si nos fijamos en lo que estamos haciendo con esta línea:

  • Ordenamos de forma aleatoria la tabla frases (normalmente es más pesado que ordenar por fecha, o por un entero)
  • Escoger el primero de la lista obtenida (esto ya no cuesta nada)

Es decir, estamos ordenando la lista por completo (de unas 2000 frases) cada vez que un usuario quiere consultar sólo 1. Por lo que al final (imaginémonos unos 30000 usuarios a la hora), hacemos muchas ordenaciones innecesarias que aumentan el uso de CPU.

Una buena solución podría ser extraer el total de filas que tenemos en la tabla (es más, no tendremos que extraerlo siempre, sino cuando añadamos o borremos información), es una consulta bastante ligera; y luego extraer un sólo elemento empezando por la fila obtenida al azar.
En el siguiente ejemplo propongo un código en PHP que obtiene una fila aleatoria de una tabla (estas líneas las extraigo de un proyecto más grande, por lo que se podrían simplificar un poco más):

1
2
3
4
5
6
$sql="SELECT COUNT(id) FROM `frases`";
$res=mysql_fetch_row(mysql_query($sql));
// Tenemos en $res[0] el número de filas
$num=rand(0, $res-1); // Obtenemos un número aleatorio.
$sql="SELECT * FROM `frases` LIMIT ".$num.",1";
$frase_elegida=mysql_fetch_array(mysql_query($sql));

He dejado un poco de lado las comprobaciones y he dado por hecho que en la tabla frases hay algún contenido. Pero creo que queda bastante clara la idea.

Puede haber más soluciones, pero creo que con esta tenemos más control sobre los resultados (podemos introducir condiciones al número y más cosas).

Categories: MySQL, PHP Tags: , , , , ,

Visita otras webs de la red