Recientemente he creado un podcast para la página de Música Vermella con el inconveniente añadido de que se suben mp3 independientes para cada publicación.

Para solucionarlo he utilizado la librería getid3 para unir los ficheros mp3 de cada publicación en un único fichero mp3.

Para verlo podéis agregar el Podcast de Música Vermella a vuestro cliente de Podcast (iTunes, Rythmbox, Banshee, Miro…).

Quería hacer un tutorial sobre cómo crear un podcast con CakePHP pero lo dejaré para otro tutorial por tal de no complicar este.

Puedes ver la segunda parte aquí: Crear un Podcast en CakePHP

Para empezar necesitaréis descargar la librería Getid3. Descargad la versión estable por si acaso ya que la versión beta falla con las etiquetas id3 (que no utilizaremos) así que si queréis utilizarla es bajo vuestra propia responsabilidad.

Getid3 versión 1.8.2 (estable)

Descomprimid el contenido del fichero que descarguéis en Getid3 y ponedlo en la carpeta /app/vendors, de manera que quede así:

1
2
3
4
/app/vendors/getid3/demos/
/app/vendors/getid3/getid3/
/app/vendors/getid3/helperapps/
/app/vendors/getid3/demás ficheros

Ahora necesitaremos el método para unir los mp3. Lo podéis encontrar en la carpeta de demos de getid3. De todos modos os dejo aquí un pequeño componente que tengo yo para utilizar getid3:

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
159
160
161
162
163
164
165
166
167
<?php
// /app/controllers/components/getid3.php
class Getid3Component extends Object
{
  public $errors = array();

  function __construct()
  {
    set_time_limit(20*3600);
    ignore_user_abort(false);
  }

  function error($text)
  {
    array_push($this->errors, $text);
  }

  function extract($filename)
  {

    App::import('vendor','getid3/getid3',array('file'=>'getid3.php'));
    // Initialize getID3 engine
    $getID3 = new getID3;
    $getID3->setOption(array('encoding' => Configure::read('App.encoding')));

    // Analyze file and store returned data in $ThisFileInfo
    $ThisFileInfo = $getID3->analyze($filename);

    return $ThisFileInfo;
  }

  function read($filename) { return $this->extract($filename); }

  function getId3Clean($filename)
  {
    $info = $this->read($filename);

    $id3 = array();
    foreach ($info['tags'] as $tag) {
      foreach ($tag as $key => $val) {
        if (empty($id3[$key])) {
          $id3[$key] = $val[0];
        }
        else {
          if (strlen($val[0]) > strlen($id3[$key])) {
            $id3[$key] = $val[0];
          }
        }
      }
    }
    return $id3;
  }

  function getCustomTags($filename)
  {
    $id3 = $this->getId3Clean($filename);
    $vars = array(
      'description' => 'content_group_description',
      'set'         => 'part_of_a_set'
    );
    foreach ($vars as $k => $v) {
      if (!empty($id3[$v])) {
        $id3[$k] = $id3[$v];
        unset($id3[$v]);
      }
    }
    return $id3;
  }

  function write($filename, $data)
  {
    App::import('vendor', 'getid3/getid3/getid3');

    // Initialize getID3 engine
    $getID3 = new getID3;
    $getID3->setOption(array('encoding' => Configure::read('App.encoding')));

    App::import('vendor','getid3/getid3', array('file' => 'write.php'));

    // Initialize getID3 tag-writing module
    $tagwriter = new getid3_writetags;

    //$tagwriter->filename       = '/path/to/file.mp3';
    $tagwriter->filename   = $filename;
    $tagwriter->tagformats = array('id3v1', 'id3v2.3');

    // set various options (optional)
    $tagwriter->overwrite_tags    = true;
    $tagwriter->tag_encoding      = Configure::read('App.encoding');
    $tagwriter->remove_other_tags = true;

    // populate data array
    $TagData['title'][]   = !empty($data['title'])?$data['title']:null;
    $TagData['artist'][]  = !empty($data['artist'])?$data['artist']:null;
    $TagData['album'][]   = !empty($data['album'])?$data['album']:null;;
    $TagData['year'][]    = !empty($data['year'])?$data['year']:null;;
    $TagData['genre'][]   = !empty($data['genre'])?$data['genre']:null;;
    $TagData['comment'][] = 'from www.underave.net';
    $TagData['track'][]   = !empty($data['track'])?$data['track']:null;;

    $tagwriter->tag_data = $TagData;

    // write tags
    if ($tagwriter->WriteTags()) {
      if (!empty($tagwriter->warnings)) {
        return $tagwriter->warnings;
      }
      return true;
    } else {
      return $tagwriter->errors;
    }
  }

  function joinMp3($file_out, $files_in)
  {
    foreach ($files_in as $nextinputfilename) {
      if (!is_readable($nextinputfilename)) {
        $this->error('Cannot read "' . $nextinputfilename . '"');
      }
    }
    if (!empty($this->errors)) return false;

    if (!is_writeable(dirname($file_out))) {
      $this->error('Cannot write "' . $file_out . '"');
      return false;
    }

    App::import('vendor', 'getid3/getid3', array('file' => 'getid3.php'));
    if ($fp_output = @fopen($file_out, 'wb')) {
      // Initialize getID3 engine
      $getID3 = new getID3;
      foreach ($files_in as $nextinputfilename) {
        $current_file_info = $getID3->analyze($nextinputfilename);
        if ($current_file_info['fileformat'] == 'mp3') {
          if ($fp_source = @fopen($nextinputfilename, 'rb')) {
            $current_output_position = ftell($fp_output);

            // copy audio data from first file
            fseek($fp_source, $current_file_info['avdataoffset'], SEEK_SET);
            while (!feof($fp_source) &amp;&amp; (ftell($fp_source) < $current_file_info['avdataend'])) {
              fwrite($fp_output, fread($fp_source, 32768));
            }

            fclose($fp_source);
            // trim post-audio data (if any) copied from first file that we don't need or want
            $end_offset = $current_output_position + ($current_file_info['avdataend'] - $current_file_info['avdataoffset']);
            fseek($fp_output, $end_offset, SEEK_SET);
            ftruncate($fp_output, $end_offset);
          } else {
            $this->error('failed to open ''.$nextinputfilename.'' for reading');
            fclose($fp_output);
            return false;
          }
        } else {
          $this->error('''.$nextinputfilename.'' is not MP3 format');
          fclose($fp_output);
          return false;
        }
      }
    } else {
      $this->error('failed to open ''.$file_out.'' for writing');
      return false;
    }
    fclose($fp_output);
    return true;
  }
}

Con este componente podéis tanto unir mp3 como leer y escribir etiquetas id3.

Evidentemente, antes de poder utilizar el componente debéis declararlo en el array de componentes de vuestro controlador:

1
2
3
class FooController extends AppController {
  $components = array('Getid3');
}

Para unir mp3 en un solo fichero no tenéis más que pasarle como primer parámetro la ruta del fichero de salida y como segundo parámetro pasarle un array con las ubicaciones de los ficheros mp3:

1
2
3
4
5
6
7
8
9
10
11
12
13
$destino = WWW_ROOT . 'files' . DS . 'podcasts' . DS . 'fichero_destino.mp3';
$mp3 = array(
  WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero1.mp3',
  WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero2.mp3',
  WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero3.mp3',
  WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero4.mp3',
  WWW_ROOT . 'files' . DS . 'mp3' . DS . 'fichero5.mp3'
);
if ($this->Getid3->joinMp3($destino, $mp3)) {
  // fichero creado correctamente
} else {
  pr($this->Getid3->errors);
}

Y con esto termina este sencillo tutorial sobre cómo crear un podcast a partir de varios mp3.

Como he dicho al inicio, pronto explicaré cómo crear el XML de dicho Podcast para que podáis agregarlo a iTunes o cualquier otro podcatcher.

Borogove es un sniffer en Python con el propósito de capturar conversarciones del chat de Facebook en una red local. Usa la técnica Man-In-The-Middle envenenando las tablas ARP.

Su uso es bastante simple, y nos hace un output de mensajes enviados por los interlocutores en tiempo real.

Para usarlo, debemos instalar las dependencias dsniff, pypcap y dpkt.

Lo mas fácil será ilustrar su uso mediante un ejemplo:

  • En nuestro escenario, **Bob** esta conectado en la misma red local que **Alice**. ** **
  • **Alice** se conecta a Internet mediante un **Router** o puerta de enlace.
  • El router tiene la IP 192.168.1.1
  • Alice tiene la IP 192.168.1.22
  • Bob tiene la IP 192.168.23
  • Bob se conecta a la red mediante la interfaz wlan0.

Lo que pretende Bob es “engañar” al Router y al PC de Alice, interfiriendo en su comunicación de forma transparente. He aquí un esquema bastante simplificado del proceso:

Una vez hecho esto, puede “inspeccionar” los paquetes que Alice envía o recibe en busca de conversaciones, sin que la víctima note nada (excepto, quizá, una conexión algo mas lenta). Dado que el chat de Facebook no funciona en HTTPS, se envía siempre en texto plano, lo qual es sumamente inseguro y permite este tipo de ataques.

Para usarlo en Ubuntu seguid los siguientes pasos:

1
2
3
4
5
sudo -s
aptitude install dsniff python-pypcap python-dpkg
wget http://borogove.googlecode.com/svn/trunk/borogove.py
chmod +x borogove.py
./borogove.py <interfaz> <IP_vicima> <gateway>

Por ejemplo, Bob lo usaría así:

1
./borogove.py wlan0 192.168.1.22 192.168.1.1

Salud y ya sabéis, usar sólo para fines educativos y bajo vuestra responsabilidad.

Hace ya mucho que existe seguramente, pero con lo escondido que lo tenían los de Cake no lo encontré hasta la semana pasada.

CakePHP Debug Kit es un plugin desarrollado por los creadores de CakePHP que nos facilita una barra de herramientas con todo lo necesario para debugar nuestra aplicación sin herramientas adicionales (vamos, que con el notepad y el debugkit tiramos millas :D).

Para descargarlo podéis hacerlo desde GitHub: https://github.com/cakephp/debug_kit/archives/master

Una vez descargado cambiadle el nombre a la carpeta por ‘debug_kit’ y ponedla en cualquiera de los directorios “plugins” de vuestra aplicación (/plugins y /app/plugins). Una vez copiado simplemente tenéis que cargar el componente Toolbar:

1
var $components = array('DebugKit.Toolbar');

… y aseguraros que vuestro nivel de debug es 2 con Configure::write('debug', 2) en el fichero core.php.

Edit: si estáis utilizando el elemento sql_dump eliminadlo de vuestro template. De lo contrario no se mostrarán las consultas en el DebugKit.

Y a partir de este momento en vuestra página web aparecerá un botón con el icono de CakePHP en la parte superior derecha. Al hacer clic nos mostrará un menú con una serie de opciones:

  • History: todavía no tengo muy claro para qué sirve.. xD
  • Session: nos muestra todos los datos guardados de la sesión actual.
  • Request: parámetros de cake, peticiones GET, POST y Cookies, además de información sobre la ruta actual (routes).
  • SqlLog
  • Timer: temporización del tiempo de ejecución de la aplicación. También muestra la memoria utilizada para la carga.
  • Log: todo aquello que guardemos con $this->log
  • Variables: otras variables de Cake ($this->data, $this->validationErrors, etc..)

Por lo que puedo leer en otras páginas el uso de esta barra de herramientas incrementa considerablemente el uso de la memoria RAM del servidor. Si tenéis problemas con ello tendréis que aumentar el memory_limit hasta al menos 128MB+.

Tampoco tiene soporte para IE6, aunque esto no creo que sea un gran problema a estas alturas :)

Rellenando el siguiente formulario puedes enviar un mensaje a los diputados/as del congreso español en relación a la aprobación de la Ley Sinde. Escríbeles lo que consideres oportuno pero sé respetuoso, solo de esta manera nuestras peticiones serán escuchadas. Una vez rellenado y enviado el formulario, entra en tu correo, tendrás que verificar un enlace para completar el envio.

Nombre:
E-mail:
Asunto:
Mensaje:
Más información: Activando esto expresas que deseas recibir información sobre futuras acciones.
Política de Privacidad xMailer copyleft Isaac Hacksimov 2009-2010, licencia GPLv3, powered by Hacktivistas.net</fieldset>

Adobe está desarrollando un IDE para crear animaciones en canvas (HTML5). Echad un ojo porque se ve realmente interesante.

</embed>

Si es que nos incitan a olvidar flash!! xD