Archivo

Archivo para la categoría ‘PHP’

Coloreando código con GeSHi

Sábado, 4 de Febrero de 2012 Gaspar Fernández Sin comentarios

geshiCuando queremos publicar código fuente por Internet (como en esta web), debemos hacer que los usuarios se sientan bien con el código y que sea agradable de leer. Además del indentado, es de agradecer la introducción de colores, que separen palabras clave, identifiquen cadenas, funciones de biblioteca, funciones propias, números y demás elementos que encontramos en un fragmento de código.

Por Internet, podemos encontrar una biblioteca muy útil para este propósito: GeSHi. Vamos a intentar hacer algo sencillo con ella.

Para instalarla simplemente tenemos que descargarla y descomprimirla en uno de los directorios de nuestra web (no tiene por qué ser el principal), a continuación vamos a hacer un pequeño programa que mostrará el código fuente de un fichero PHP. Suponemos que geshi.php está situado en el mismo directorio que este ejemplo:

1
2
3
4
5
6
7
8
9
10
<?php
// Basado en los ejemplos de la página oficial
require_once("geshi.php");

$codigo=file_get_contents('mi_programa.php');

$ges=new GeSHi($codigo, 'php');

echo $ges->parse_code();
?>

Con este pequeño ejemplo, se mostrará de forma coloreada el código seleccionado, aunque es conveniente el uso de cachés, es decir, es una buena idea almacenar el código coloreado, es decir, el contenido que devuelve $ges->parse_code() en un archivo aparte y cargar directamente este archivo en la siguiente petición de la página. Por ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
include_once 'geshi.php';

function color_source_file($source_file, $language)
{
  $source_cache='cache/'.basename($source_file).'_'.$language.'.cache';
  if (@filemtime($source_cache)<filemtime($source_file))
    {
      $geshi= new GeSHi(file_get_contents($source_file), $language);
      $highlighted_source=$geshi->parse_code();
      file_put_contents($source_cache, $highlighted_source);
      return $highlighted_source;
    }
  return file_get_contents($source_cache);
}

$source = 'mi_programa.php';

echo color_source_file($source, 'php');
?>

Este código es capaz de guardar en un fichero el html generado por GeSHi en un archivo de caché (se guardará en un directorio llamado cache, el nombre del fichero será el mismo que el espeficado y su formato será [nombre]_[lenguaje].cache . La decisión se toma en base a las fechas de modificación de los archivos. Si el archivo de caché no existe (por eso la @ para que no devuelva fallos PHP) o su fecha de modificación es anterior a la fecha de modificación del archivo fuente, se generará un nuevo archivo de caché y se devolverá el código coloreado. Si no, se devolverá el código coloreado leyendo directamente del archivo de caché.

Activar números de línea

Lo podemos hacer así:

1
$ges->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS);

Si ponemos GESHI_FANCY_LINE_NUMBERS cada 5 líneas saldrá el número en negrita, si ponemos GESHI_NORMAL_LINE_NUMBERS no sucederá así.

Resaltar líneas

Para resaltar líneas, debemos crear un array con los números de línea que queremos resaltar:

1
$lineas=array(5,6,7,43,53,54)

Y luego escribir:

1
$ges->hightlight_lines_extra($lineas);

Personalizando los estilos

Para ello podemos utilizar CSS. Por defecto GeSHi personaliza el style=”" de cada etiqueta, aunque genera mucho código html que podemos ahorrar. Para ello, podemos utilizar lo siguiente:

1
2
$ges->enable_classes();
file_put_contents('codigo.css', $ges->get_stylesheet(false));

Así crearemos un archivo .css que contendrá todos los estilos que puede tener un código fuente en un determinado lenguaje (en el cual hemos inicializado la clase), luego podemos incluir ese CSS ya generado en nuestro html resultante, y cambiar los colores, tipos de letra, etc.

GeSHi tiene muchísimas más opciones, para saber más, basta con un vistazo a la documentación oficial (en inglés) para descubrir todas las posibilidades de esta clase.

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.

Publicando mensajes en Facebook sin que el usuario esté ahora mismo en la web [ modo offline ]

Viernes, 27 de Enero de 2012 Gaspar Fernández Sin comentarios

enchufe

Una de las grandes utilidades que nos da Facebook por si creamos una aplicación de escritorio, o una aplicación web que publique posts de nuestro blog automáticamente en nuestro muro, son los mensajes Offline, con este modo, no es necesario que un usuario esté identificado realmente en Facebook, aunque, debemos tener cuidado a la hora de trabajar con la aplicación, los usuarios nos han dado permiso para publicar en su nombre contenidos que nosotros generamos, por lo que debemos evitar que se pueda acceder a la publicación de contenidos directamente. Es decir, lo que voy a mostrar ahora es un mero ejemplo de cómo se haría, aunque muestro un programa que es lo más inseguro del mundo, ya que, cualquiera que entre en la dirección web especificada podrá escribir en Facebook con nuestro ID de usuario.

Creando la aplicación y practicando la publicación

Para esto, hay dos posts anteriores que te recomiendo leer si no lo has hecho ya:

Creando dos interfaces

Por un lado necesitamos la interfaz que conecta con Facebook, tal y como la hemos hecho ya en el post anterior, desde aquí se pedirá permiso para poder publicar mensajes, y para poder acceder de forma offline. Este será nuestro index.php en los ejemplos (aunque podemos cambiarlo por cualquier página que destinemos a la identificación en Facebook).

Por otro lado, necesitamos el script que realmente va a publicar texto en Facebook, este script no debe identificarse en el sistema, sólo debe enviar la publicación (será en el ejemplo publica.php)

El código fuente completo podrás verlo y descargarlo al final del post.

Pidiendo permiso

Para escribir en Facebook con el modo offline, debemos pedir el permiso, concretamente el permiso offline_access. Con este permiso la palabra clave que nos da acceso con el usuario elegido no caducará (las claves normales, sin offline access, tienen una caducidad limitada, aunque funcionarán durante un tiempo (¿minutos?) aunque el usuario haya dejado de estar activo).

Para manejar los permisos de Facebook de una mejor forma, he extendido la clase Facebook con algunos métodos que nos ayudarán a la hora de pedir permisos:

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
<?php
  /**
   *************************************************************
   * @file facebook_ext.php
   * @brief Extensión de la clase Facebook que permite manejar
   *        algunas opciones de forma más intuitiva.
   *
   * @author Gaspar Fernández <blakeyed@totaki.com>
   * @version
   * @date 14 ene 2012
   * Historial de cambios:
   *
   *
   *
   *************************************************************/


require ('facebook.php');

class FacebookExtended extends Facebook
{
  private $permissions=false;

  function __construct($config)
  {
    parent::__construct($config);
  }

  function askForPermission($ext_perm, $uid=false)
  {
    if (!$uid)
      $uid=$this->getUser();

    if (!$this->permissions)
      $this->permissions=$this->api('/'.$uid.'/permissions');
   
    if ( (isset($this->permissions['data'])) && (isset($this->permissions['data'][0])) )
      return $this->permissions['data'][0][$ext_perm];
  }

  function askForPermissions($ext_perms, $uid=false)
  {
    $permArray = explode(",", $ext_perms);

    $permissionsOk=true;

    $nElems=count($permArray);
    for ($i=0; $i< $nElems; $i++)
      {
    $ext_perm=trim($permArray[$i]);
    if ($ext_perm!='')
      {
        /* Internal debug */
        /* echo $i.'-'.$this->askForPermission($ext_perm, $uid)."<br>"; */
        $permissionsOk= ($this->askForPermission($ext_perm, $uid) && $permissionsOk);
      }
      }
    return $permissionsOk;
  }

  function loginUser($permissions)
  {
    if ($permissions)
      $loginUrl=$this->getLoginUrl(array('scope'=>$permissions));
    else
      $loginUrl=$this->getLoginUrl();

    header('Location: '.$loginUrl);
    exit;
  }

};
?>

Esta clase, se encargará de preguntar por los permisos que necesitamos de forma automática (en realidad fue como se explicó en el post anterior, aunque cuando tenemos que preguntar por varios permisos nuestro código puede crecer bastante).

Ahora, para pedir permiso haremos lo sigueinte:

1
2
3
4
$permissions = $facebook->askForPermissions('publish_stream,offline_access');
   
  if (!$permissions)
    throw new Exception('No tengo permisos suficientes', NO_PERMISSIONS);

La excepción podemos crearla como queramos, yo he seguido la técnica del post anterior, que podréis observar mejor con el código completo, lo que está claro es que el código no debe continuar pasado este punto, y debemos pedir los permisos necesarios. Además, a la hora de pedir los permisos, con la clase que hemos visto anteriormente, podemos hacer lo siguiente:

1
$facebook->loginUser('publish_stream,offline_access');

Con lo que también nos ahorramos unas líneas de código.

También, para publicar en nombre de los usuarios debemos obtener un Access Token, es una palabra de acceso única que identifica al usuario de Facebook en nuestra aplicación y nos permite interactuar, para ver esta palabra debemos hacer:

1
echo $facebook->getAccessToken();

Publicando contenido

Para publicar contenido, ahora hemos creado el archivo publica.php que sólo publicará contenido en el muro, con este archivo tenemos que tener especial cuidado, ya que en este caso, cualquiera podrá publicar contenido nada más accediendo al archivo (Código fuente de 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
<?php

$api_key = 'Rellenar con nuestra API key';
$api_sec = 'Rellenar con nuestra API secret';

require_once('facebook_ext.php');

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

try
{
  $destino="gaspy";     // O el nombre de usuario que queramos usar
  $public='Probando mensajes automáticos con el modo offline';
  $access_token='palabra que vimos cuando nos autorizamos, muy laarga';

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

Ahora, para publicar contenido, en la llamada a la API debemos especificar:

  • uid = UID con la que queremos publicar, es decir, el usuario en nombre de quién hablamos.
  • message = Mensaje que queremos publicar
  • access_token = Palabra de acceso

Es más, podemos publicar en el muro o la página de quien queramos con esta técnica, igual que hacíamos antes, pero en este caso, lo hacemos sin que tengamos que estar identificados como ese usuario.

Código fuente de index.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
<?php

$api_key = 'Rellenar con nuestra API key';
$api_sec = 'Rellenar con nuestra API secret';

require_once('facebook_ext.php');

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

$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('publish_stream,offline_access');
   
  if (!$permissions)
    throw new Exception('No tengo permisos suficientes', NO_PERMISSIONS);
 
  echo "No tienes que hacer nada, cierra esta ventana.";
}
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('publish_stream,offline_access');
      break;

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

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

Para descargar el código fuente: modooffline.tar.bz2 (1.7Kb)
Hay que incluir la API de Facebook para que funcione y sustituir $api_key y $api_sec por nuestra API Key y API secret respectivamente.

Foto: Samuel M. Livingston (Flickr)

Guardando un informe en nuestros proyectos PHP

Martes, 24 de Enero de 2012 Gaspar Fernández Sin comentarios

130120125882

Muchas veces, los proyectos en PHP crecen y crecen, y pueden ocurrir múltiples errores, tanto a la hora de crearlos como cuando ya están entregados al cliente final y debemos ofrecer soporte.

Por eso es importante ser rápido localizando los errores, y, siempre que la página, o el programa no haga algo como debe, debería tomar nota de qué ha pasado, cómo ha sido y de los datos involucrados con el fin de poder solventar el problema. Tengo que decir que debemos ser inteligentes con estos criterios, ya que un usuario malintencionado puede hacernos perder todo el espacio que tengamos disponible en nuestro servidor provocando errores; por ejemplo un script que funcione en Ajax y no se le hayan entregado los parámetros necesarios, puede ser útil saberlo en tiempo de desarrollo, pero no cuando el proyecto esté funcionando en la web, puede que incluso un motor de búsqueda mal entrenado se dedique a entrar en ese script y tumbarnos el programa.

Para hacer un informe, lo más fácil es hacerlo en un fichero de texto (podemos crear un XML sin mucho esfuerzo más, aunque va a ser algo que sólo vamos a leer nosotros y como mucho los administradores de la página, en muchos casos a los administradores no les dejaremos verlo).

Para esto, yo dispongo de una clase con funciones para guardar un informe de errores:

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
150
151
152
153
154
155
156
157
158
<?php

  // Activa la depuración
define('__debug', true);

// Activa la visualización de los errores (sólo para modo desarrollo)
define('__debug_v', true);

class my_logger
{
  private $base_path;

  function __construct()
  {
    /** Sólo actuaremos si __debug es verdadero  */
    if (__debug)
      {
    define('__debug_file', 'my_log.log');
    define("__gf_dateformat_log", "d/m/Y H:i");

    // Si ejecutamos el programa desde consola. El directorio actual es PWD
    if (isset($_SERVER['DOCUMENT_ROOT']))
      $base_path=$_SERVER['DOCUMENT_ROOT'];
    elseif (isset($_SERVER['PWD']))
      $base_path=$_SERVER['PWD'];
    else
      $base_path='';
      }    
  }

/**
 ******************************************************************
 * @brief Escribir mensaje de error en pantalla
 *
 * To-do: Posibilidad de crear plantillas para este error desde el archivo de configuración
 *
 * @param $emsj    Mensaje de error
 *
 * @return Nada
 *
 ******************************************************************/

  private function displayerror($emsj)
  {
    return '<br /><span style="color: yellow;"'.wordwrap('DEP: '.$h->T($msj),70,"\n").'</span><br />';
  }

/**
 ******************************************************************
 * @brief Extrae el nombre de una función o un método de un array
 * de backtrace
 *
 * @param $bt_data  Array de backtrace
 * @param $index    Índice del array
 *
 * @return Array[3]={linea, Función o método (clase::metodo), fichero}
 *
 ******************************************************************/

  private function backtrace_function (&$bt_data, $index)
  {
    $bt_single=(isset($bt_data[$index]))?$bt_data[$index]:false;
    if (!$bt_single)        /* No data, no function */
      return false;

    $function=(isset($bt_single['function']))?$bt_single['function']:false;
    $class=(isset($bt_single['class']))?$bt_single['class']:false;
    $funcname=($class)?($class.'::'.$function):$function;
   
    $file=str_replace('path', '', $bt_single['file']);
    return array($bt_single['line'], $funcname, $file, $file.' ('.$funcname.', '.$bt_single['line'].')');
  }

  /**
 ******************************************************************
 * @brief Genera un fragmento de un error complejo. A menudo, esto
 *        incluye información del backtrace u otras cosas.
 *        Este método debe ser llamado desde preg_replace_callback()
 *
 * @param $data Datos enviados por preg_replace_callback()
 *
 * @return En qué se tiene que convertir la cadena enviada.
 *
 ******************************************************************/

  private function complexError($data)
  {
    if (!isset($data[1]))
      return $this->writelog('%%where%%: No se ha llamado desde preg_replace_callback(); Origen: "%%origen%%"');

    $btrace=debug_backtrace();

    switch ($data[1])
      {
      case 'where':
    $wdata=$this->backtrace_function ($btrace, 4); /* Nivel 0: complexError; Nivel 1:preg_replace_callback(); Nivel 2: writelog;  Nivel 3: wlog(); Nivel 4: El que queremos */
    return $wdata[3];
    break;
      case 'origen':
    $wdata=$this->backtrace_function ($btrace, 5); /* Nivel 3: dónde llamamos a la función */
    return $wdata[3];
    break;
      case '-origen':
    $wdata=$this->backtrace_function ($btrace, 6); /* Nivel 3: dónde llamamos a la función */
    return $wdata[3];
    break;
      case '--origen':
    $wdata=$this->backtrace_function ($btrace, 7); /* Nivel 3: dónde llamamos a la función */
    return $wdata[3];
    break;
      default:
    return $this->writelog('%%where%%: No se encuentra la palabra clave: "'.$data[1].'"');
    break;
      }
  }

/**
 ******************************************************************
 * @brief Escribimos un mensaje en el log.
 *
 * @param $error     Error a escribir
 * @param $display   Mostrar error en pantalla (sólo si __debug_v vale true)
 *
 * @return false para usarlo como return de alguna función
 *
 ******************************************************************/

  function writelog($error, $display=false)
  {
    if ((__debug) && ($error))
      {
    $errorw=preg_replace_callback('/%%(.*?)%%/', array($this, 'complexError'), $error);
    $log_f = fopen(__debug_file, "a+");
    fputs($log_f, date(__gf_dateformat_log)." - ".$errorw."\n");
    fclose($log_f);

    if ((__debug_v)&&($display))
      $this->displayerror($errorw);
      }
    return false;
  }
};

$log = new my_logger();

function wlog($error, $display=false)
{
  $GLOBALS['log']->writelog($error, $display);
}

function genera_error()
{
  wlog("Genero un error nada más empezar y digo dónde está %%where%% llamado por %%origen%%");
}

function original()
{
  genera_error();
}

original();
?>

Cada vez que encontramos un error, podemos llamar a wlog() para guardar el informe del error que se guardará en un archivo de texto.

Mientras estamos desarrollando la aplicación podemos definir __debug_v a true para visualizar algunos errores (que previamente enviaremos con wlog(”error”, true)).

Además, a la hora de enviar un error, disponemos de las palabras clave %%where%%, %%origen%%, %%-origen%% y %%–origen%% para identificar automáticamente en qué función se ha producido el error, desde qué línea se llama así como la función desde donde se llama a la que provoca el error, y la anterior…

Si utilizamos la opción para averiguar automáticamente dónde está el error (la alternativa sería escribir el nombre de la función en el texto del error) tardará un tiempo en ejecutarse, ya que estamos escrudiñando dónde se ha producido, estamos haciendo un backtrace. De hecho la función PHP que genera ese informe es debug_backtrace() y nos resultará de gran ayuda para la depuración de nuestras aplicaciones.

Escribiendo en muros desde nuestra aplicación de Facebook

Domingo, 22 de Enero de 2012 Gaspar Fernández Sin 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.

Creando una aplicación para Facebook (paso a paso)

Miércoles, 18 de Enero de 2012 Gaspar Fernández 2 comentarios

monitor_poesia

He decidido hacer esta guía porque Facebook anda cambiando los métodos para hacer aplicaciones y varias partes de su API. Los chicos de Facebook no paran de meter y sacar cosas y no dejan la página quieta. Después de hacer varias guías para “publicar definitivamente” en Facebook, van y cambian la forma de hacerlo.

Aunque parece que se han estabilizado, todos estos cambios han sido para llegar a la Graph API, se ha quedado bien hecha y estable, y yo creo que es posible aprender mucho de ella.

Aunque en esta guía empezaré desde el principio, desde que se crea la aplicación, paso a paso, ya que actualmente crear una aplicación vale para muchas cosas, no sólo para algo que resida dentro de Facebook sino para webs o clientes que funcionan fuera de Facebook e interactúan con la red social.

He de decir también que esta guía está hecha en Enero de 2012, por lo que si entras aquí en el futuro, puede que hayan hecho otro cambios definitivo más en Facebook.

Primer paso: Crear la App

Para ello debemos dirigirnos a https://developers.facebook.com/apps. Éste será nuestro centro de control de aplicaciones, donde podremos ver y editar los datos de éstas. Allí encontraremos en la parte superior de la página:

facebook_create_app

Pulsamos sobre Create New App, tras ello veremos un diálogo como este:

facebook_create_app_dialogEn el que en:

  • App Display Name debemos decir el nombre de nuestra aplicación, o si es una aplicación para identificarnos en una página, el nombre de la página. Es un nombre que la identifique.
  • App Namespace es el nombre que tiene nuestra aplicación en la URL de aplicaciones de Facebook. Es decir https://apps.facebook.com/AppNamespace . Dependiendo del ámbito de nuestra aplicación (si es accesible a través de Facebook.com o no) rellenaremos este campo o no.

Si continuamos, a veces la web de Facebook dará un error (comprobado el 7 de Enero de 2012), por lo que podemos volver a la página de las aplicaciones y continuar.

En la configuración de la aplicación, le damos a Edit Settings, y saldrá una pantalla así:

facebook_app_basica

Aquí podremos rellenar el Namespace (mencionado antes), el mail de contacto y el dominio donde está alojada la aplicación (muy importante, ya que si la aplicación no está en el dominio indicado, no funcionará; además de la categoría de nuestra aplicación.

Por otra parte, arriba vemos la App ID y la App Secret. La primera es el identificador de nuestra aplicación, y la segunda una clave secreta que no se debe compartir con nadie para que la aplicación pueda interactuar con Facebook, algo así como el nombre de usuario y contraseña de nuestra aplicación. (Yo lo he puesto aquí, pero en realidad lo he regenerado varias veces).

La aplicación que crearemos servirá para enlazar una página web con Facebook y poder utilizar esa información, para eso debemos rellenar el apartado App Domain (por ejemplo minutodecaos.com), con el dominio donde estén alojadas las páginas de la aplicación, si no, la aplicación no estará autorizada y, un poco más abajo Site URL con la dirección exacta donde estará alojada nuestra aplicación.

fb_website

Código fuente de la App

Es hora de crear nuestra aplicación en PHP. Lo primero que tenemos que hacer es descargarnos los archivos de la API desde esta dirección, dentro de GitHub. En principio trabajaremos en la web en modo local, por lo que creamos un directorio en nuestro disco duro (proyectos/facebook/tests/ dentro de mi home) Y descomprimimos los archivos dentro del directorio de nuestro proyecto. Aunque no es estrictamente necesario, yo lo he descomprimido dentro de lib/facebook, por lo que esos archivos estarán en $HOME/proyectos/facebook/tests/lib/facebook; y creamos el siguiente index.php (que luego subiremos al servidor junto con los ficheros de biblioteca de Facebook) :

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

$api_key = 'xxxxxxxxxx';
$api_sec = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

require_once('lib/facebook/facebook.php');

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

$sesion = $facebook->getUser();
if ($sesion)
  {
    echo "Estamos identificados en Facebook<br/>";
  }
 else
  {
    echo "No estamos identificados en Facebook ";
    $login_url = $facebook->getLoginUrl();
    echo '<a href="'.$login_url.'">Click para identificarte</a>';
  }

?>

Este código nos mostrará, la primera vez que entremos: “No estamos identificados en Facebook. Click aquí para identificarte”, eso no significa que no hayamos entrado a la página de Facebook, significa que la página web no te ha identificado como usuario y de ser autorizada, por eso hacemos click en la pantalla anterior y aparecerá lo siguiente:
fb_website1

Login automático

Si no queremos mostrar el enlace para identificarnos en la aplicación, podemos utilizar el siguiente código:

1
2
3
4
5
6
7
8
if ($sesion)
   echo "Estamos identificados en Facebook";
else
{
   $login_url = $facebook->getLoginUrl();
   header('Location: '.$login_url);
   die();
}

Mostrando datos de usuario, o cogiéndolos

En la parte de “Estamos identificados en Facebook”, podemos hacer:

1
2
3
4
5
6
7
if ($sesion)
{
   echo "Estamos identificados en Facebook<br/>";
   echo "Usuario: ".$sesion."<br/>";
   $userData = $facebook->api('/me');
   echo nl2br(print_r($userData, true));
}

Con estas líneas podemos ver información del usuario que está actualmente identificado en nuestra aplicación, y podremos utilizar los datos del array $userData:

  • ['name'] - Nombre completo del usuario
  • ['first_name'] - Nombre
  • ['last_name'] - Apellidos
  • ['link'] - Enlace a la página del usuario en Facebook
  • ['username'] - Nombre de usuario de Facebook
  • ['about'] - Frase personal
  • ['gender'] - Género
  • y mucho más que podemos ver cuando ejecutamos el ejemplo anterior

Ahora en Facebook, siempre que queramos acceder a información tanto de páginas, grupos, usuarios, etc, sólo tenemos que acceder a través de la llamada a api(’/localizacion’), con la palabra especial /me, como hemos visto para el usuario actual. Esto nos puede ayudar a identificarnos en nuestra web, sin pedir usuario, ni contraseña, a través de la Graph Api.

Conocer uptime del servidor con PHP

Viernes, 13 de Enero de 2012 Gaspar Fernández Sin comentarios

En ocasiones, sobre todo en nuestros paneles de administración, a veces es necesario, o bonito, conocer cuánto tiempo lleva el servidor encendido, así vemos si nos han reseteado la máquina o incluso alardear de que nuestro servidor lleva encendido más tiempo que otro.

Para ello, yo uso 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
/**
 ******************************************************************
 * @brief Obtiene un array con la información del uptime
 *
 * @return array('days'=> , 'hours'=> , 'minutes'=> , 'seconds'=>
 *         o falso si no se puede leer /proc/uptime
 *
 ******************************************************************/

  function getUptime()
  {
    $info = @file_get_contents("/proc/uptime");
    if (!$info)
      return false;

    $desglos = explode(" ", $info);

    $segundos = intval($desglos[0] % 60);
    $minutos = intval($desglos[0] / 60 % 60);
    $horas = intval($desglos[0] / 3600 % 24);
    $dias = intval($desglos[0] / 86400);
     
    return array('days'    => $dias,
         'hours'   => $horas,
         'minutes' => $minutos,
         'seconds' => $segundos);

  }

Donde obtenemos en un array los días, horas, minutos y segundos, directamente podemos hacer:

1
print_r(getUptime());

Si quieremos una salida bonita, podemos hacer lo 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
/**
 ******************************************************************
 * @brief Expresa un número con su unidad. Si el número es 1, pone la unidad en singular, si es >1, lo pone el plural
 *
 * @param $numero    Número a presentar
 * @param $singular  Unidad en singular
 * @param $plural    Unidad en plural
 * @param $coma      Texto a presentar delante de la cantidad (por ejemplo, una coma)
 * @param $sicero    Texto a presentar si el número es cero
 * @param $desp      Texto a presentar después de la cantidad
 *
 * @return Texto formateado
 *
 ******************************************************************/

function cuenta($numero, $singular, $plural, $coma=false, $sicero=false, $desp=false)
{
  if ($numero>1)
    $out=$numero.$plural;
  elseif ($numero==1)
    $out=$numero.$singular;
  else
    $out=$sicero;

  if ($out)
    $out=$coma.$out.$desp;
 
  return $out;
}

function returnUptime()
{
  $o='';
  $uptime=getUptime();
  if (!$uptime)
    throw new Exception ("No se puede acceder a /proc/uptime");

  if ($uptime['days'])
    $o.=cuenta($uptime['days'],' día', ' días', ($o!='')?', ':'', '', '');

  if ($uptime['hours'])
    $o.=cuenta($uptime['hours'],' hora', ' horas', ($o!='')?', ':'', '', '');

  if ($uptime['minutes'])
    $o.=cuenta($uptime['minutes'],' minuto', ' minutos', ($o!='')?', ':'', '', '');

  if ($uptime['seconds'])
    $o.=cuenta($uptime['seconds'],' segundo', ' segundos', ($o!='')?', ':'', '', '');


  return $o;
}

echo returnUptime();

cuenta() es una función que hice hace mucho mucho tiempo y a la que le tengo mucho cariño, y me ayuda a hacer la salida más amigable para el usuario. Aunque tenéis el comentario para Doxygen encima, aquí relato sus argumentos:

  • $numero : Es el número que vamos a mostrar por pantalla, puede ser cualquier número
  • $singular : Muestra la unidad en la que está expresado el número, además, este texto se mostrará sólo si el número es 1.
  • $plural : Es igual que el anterior, pero se mostrará cuando la unidad es distinto a 1.
  • $coma : Es un texto que se representa antes de la unidad, por ejemplo una coma, si vamos a enumerar, como en este ejemplo del uptime
  • $sicero : Este texto se mostrará si $numero es 0
  • $desp : Será un texto que se muestre después de la cadena generada

La función getUptime() producirá una excepción en servidores Windows o, en sistemas donde no tengamos acceso a /proc/uptime ; por supuesto el cliente puede estar corriendo cualquier sistema operativo.

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';

C.I. XII: La evolución de la web, 20 aniversario de Linux, DateTime para php, instalar Arch Linux, Creando una aplicación en Android y un pedal con Arduino

Domingo, 4 de Septiembre de 2011 Gaspar Fernández Sin comentarios

Me gustaría esta vez compartir algunos enlaces que me han llamado la atención:

Categories: Arduino, C/C++, General, Linux, PHP, curioso Tags:

C.I. X: Creando un Framework PHP, Microsoft y Nokia a lo suyo, mejores momentos para publicar, clones libres de juegos

Domingo, 3 de Julio de 2011 Gaspar Fernández Sin comentarios

Una pequeña recopilación de enlaces de estos días:

Visita otras webs de la red