Material: Integrando PHP5 y AS3 a través de AMF

Dejo aquí todo el material de la charla que ofrecí en la PHPConfrence el viernes:

Slides

Integrando ActionScript3 y PHP5 a través de AMF

Ejemplo 1: Chat AMF

Flex + WebOrb Chat
AMF File Chat: Chat realizado con WebOrb para PHP + Flex.
Se puede ver en acción la implementación de mensajería de WebOrb para PHP y un sistema de transferencia de archivos a través del canal del Chat.

Ejemplo 2: Gestor Contactos

Gestor Contactos multi AMF implementation
Gestor de Contactos realizado con PHP + Flex. Se puede ver cómo con una misma base de código, solo cambiando las rutas de los gateways AMF se puede atacar a un mismo servicio a través de las diferentes implementaciones presentadas: Weborb, AMFPHP y Zend_AMF.
Nota 1: Zend framework debe estar instalado en el include_path de PHP para que funcione con Zend_AMF. Las demás implementaciones funcionan out of the box.
Nota 2: Se debe crear la base de datos MySQL gestor_contactos y ejecutar el script SQL contra ésta para crear la tabla contacto.

Enjoy!

Doctrine: ORM Open Source para PHP 5.2+

Doctrine es un potente y completo sistema ORM (object relational mapper) para PHP 5.2+ con un DBAL (database abstraction layer) incorporado.

Justo lo estoy utilizando para un proyecto y estoy empezando a ver su potencial, pero de la documentación se puede extraer que tiene todas las características necesarias para ser funcional en (casi?) cualquier proyecto.

Entre muchas otras cosas tienes la posibilidad de exportar una base de datos existente a sus clases correspondientes y también a la inversa, es decir convertir clases (convenientemente creadas siguiendo las pautas del ORM) a tablas de una base de datos.
Por otro lado, como la librería es bastante grande ésta tiene un método para ser ‘compilada’ al pasar a producción.
Dejo un índice de temas que estoy utilizando para buscar referencias durante el desarrollo:

Evitar Subqueries con Joins

Una petición típica en una relación de uno a n es saber qué relaciones no se han dado todavía en un momento dado.

Por ejemplo, teniendo estas tablas (sacado de una duda de un lector):

MySQL:
  1. CREATE TABLE noticia (
  2.   id_noticia INT(11) NOT NULL AUTO_INCREMENT,
  3.   id_categoria INT(11) NOT NULL,
  4.   noticia TEXT NOT NULL,
  5.   PRIMARY KEY  (id_noticia)
  6. ) TYPE=MyISAM;
  7. CREATE TABLE categorias(
  8.     id_categoria INT(11) NOT NULL AUTO_INCREMENT,
  9.     nombre_categoria TEXT NOT NULL,
  10.     PRIMARY KEY(id_categoria)
  11. ) TYPE=MyISAM;

Queremos sacar todas las categorías que no tienen ninguna noticia relacionada.
Para ello podemos hacer dos cosas, utilizar una subquery para la que tendremos que disponer de MySQL 4.1 o superior , o utilizar un LEFT JOIN.
En este caso concreto voy a utilizar un LEFT JOIN:

MySQL:
  1. SELECT DISTINCT
  2.   cat.nombre_categoria
  3. FROM
  4.   categorias AS cat
  5. LEFT JOIN
  6.   noticia AS new
  7. ON
  8.   cat.id_categoria = new.id_categoria
  9. WHERE
  10.   new.id_categoria IS NULL

Enlaces relacionados:
* INNER JOIN o EQUI-JOIN :: Consultas MySQL..

Pack de herramientas gratuitas

Siempre va bien saber qué herramientas utiliza otra gente para ver si nos estamos perdiendo algo.
Es por esto que he decidido poner un listado de las herramientas gratuitas que utilizo actualmente.
Si alguien sabe de alguna que cree que me falta, por favor que lo diga :)

Formateando el código ( source code formatters )

A veces trabajando con código de otra gente encuentras que, o bien el código carece de estilo y está completamente desordenado o el estilo no es de tu agrado y te dificulta la lectura.
Otras veces simplemente quieres arreglar algo que has hecho de una manera fácil y rápida.
En cualquier de los dos casos hay una solución a la que yo personalmente acudo con frecuencia. Son los formateadores de código (code formatters).
A medida que los vas necesitando vas viendo que hay gente por ahí que se ha dedicado a crear un buen repertorio de ellos.
Este es un listado de algunos que he encontrado gratuitos:

SQL:
- SQLInform

ActionScript, PHP:
- SEPY

HTML:
- Tidy
- TidyUI (Entorno gráfico para Tidy)

JavaScript:
- JavaScript code improver

Java:
- JALOPY

Delphi:
- JEDI

PHP, Java, C++, C, Perl, JavaScript, CSS:
- Pretty Printer

Seleccionar varias veces la misma tabla en la cláusula SELECT

Me he encontrado con el siguiente problema:
Tengo una tabla en la que tengo que sacar valores relacionados de la misma tabla dos veces.
Por ejemplo, siguiendo el ejemplo del post sobre INNER JOIN creamos la base de datos contactos si no la tenemos y las tablas clientes, localidades y tipos_clientes con la diferencia que añadiremos un campo más en clientes.

Para modificar la tabla "clientes":

MySQL:
  1. ALTER TABLE
  2.     contactos.clientes
  3. ADD COLUMN
  4.     lugar_procedencia INT(3) UNSIGNED NOT NULL
  5. AFTER
  6.     localidad;

Ahora tenemos un nuevo campo llamdo lugar_procedencia que vamos a rellenar de la siguiente manera:

MySQL:
  1. UPDATE clientes SET lugar_procedencia=1 WHERE id = 1;
  2. UPDATE clientes SET lugar_procedencia=2 WHERE id = 2;
  3. UPDATE clientes SET lugar_procedencia=3 WHERE id = 3;
  4. UPDATE clientes SET lugar_procedencia=2 WHERE id = 4;

Una vez hecho esto ya podemos ver como se hace el select para poder sacar valores de la tabla localidades dos veces de una sola vez:

MySQL:
  1. SELECT
  2.     clientes.nombre AS nombre,
  3.     localidad_actual.nombre_localidad      AS localidad,
  4.     localidad_procedencia.nombre_localidad AS procedencia,
  5.     tipos_cliente.tipo AS tipo_cliente
  6.  
  7. FROM
  8.     clientes,
  9.     localidades AS localidad_actual,
  10.     localidades AS localidad_procedencia,
  11.     tipos_cliente
  12.  
  13. WHERE
  14.     clientes.localidad = localidad_actual.id AND
  15.     clientes.lugar_procedencia = localidad_procedencia.id AND
  16.     clientes.tipo_cliente = tipos_cliente.id;

Esto devolverá el siguiente resultado:

nombre localidad procedencia tipo_cliente
Marcos Gonzalez Oviedo Oviedo Desarrollador
Daniel Aguilar Barcelona Barcelona Desarrollador
Abel Molina Barcelona Girona Diseñador
Ingeniería y Mezclas Girona Barcelona Otros

Lo que hemos hecho es asignar un alias diferente a la misma tabla para que MySQL la procese como si fuera otro campo:

(...)
localidades AS localidad_actual,
localidades AS localidad_procedencia
(...)

de lo contrario trataría a los dos campos como uno y el resultado no sería el esperado.
Además hemos tenido éso en cuenta en la cláusula WHERE para que MySQL sepa bien donde estamos buscando las relaciones.

Enlaces relacionados:
* ...Consultas MySQL a multiples tablas relacionadas

INNER JOIN o EQUI-JOIN :: Consultas MySQL a multiples tablas relacionadas

Desde MySQL es posible realizar una consulta que devuelva los valores de una tabla que está relacionada con otras de una sola vez.
Por ejemplo, tenemos una tabla principal bien normalizada, con muchos campos que estan relacionados mediante un id con otras tablas que contienen los valores reales.
Lo que necesitamos hacer es convertir esa tabla ppal en otra en que los IDs se conviertan en dichos valores reales, y para ello utilizaremos JOINs:
Hay varios tipos de JOIN:

- Cross-Join
- Equi-Join o Inner Join
- Left Join

En este ejemplo se verá la utilización de lo que se llama un Equi-Join o Inner Join.
Para ver el funcionamiento creamos una base de datos de ejemplo:

MySQL:
  1. CREATE DATABASE contactos;
  2. USE contactos;
  3.  
  4. CREATE TABLE clientes   (
  5.             id INT(3),
  6.             nombre VARCHAR(100),
  7.             tipo_cliente INT(2),
  8.             localidad INT(3)
  9.             );
  10.  
  11. CREATE TABLE tipos_cliente
  12.             (
  13.             id INT(2),
  14.             tipo VARCHAR(255)
  15.             );
  16.  
  17. CREATE TABLE localidades
  18.             (
  19.             id INT(3),
  20.             nombre_localidad VARCHAR(255)
  21.             );
  22.  
  23. # rellenamos la tabla "clientes"
  24. INSERT INTO clientes VALUES ( 1, 'Marcos Gonzalez', 1, 1 );
  25. INSERT INTO clientes VALUES ( 2, 'Ingeniería y Mezclas', 3, 2 );
  26. INSERT INTO clientes VALUES ( 3, 'Daniel Aguilar', 1, 3 );
  27. INSERT INTO clientes VALUES ( 4, 'Abel Molina', 2, 3 );
  28.  
  29. #rellenamos la tabla tipos_cliente
  30. INSERT INTO tipos_cliente VALUES ( 1, 'Desarrollador' );
  31. INSERT INTO tipos_cliente VALUES ( 2, 'Diseñador' );
  32. INSERT INTO tipos_cliente VALUES ( 3, 'Otros' );
  33.  
  34. # rellenamos la tabla localidades
  35. INSERT INTO localidades VALUES ( 1, 'Oviedo' );
  36. INSERT INTO localidades VALUES ( 2, 'Girona' );
  37. INSERT INTO localidades VALUES ( 3, 'Barcelona' );

Y ahora la consulta:
Lo que queremos hacer es recoger todos los valores de la tabla clientes pero recogiendo el valor real de los Id's, que está situado en otras tablas relacionadas.

MySQL:
  1. SELECT
  2.     clientes.nombre AS nombre_cliente,
  3.     localidades.nombre_localidad AS localidad_cliente,
  4.     tipos_cliente.tipo AS tipo_cliente
  5. FROM clientes,
  6.     localidades,
  7.     tipos_cliente
  8. WHERE clientes.localidad=localidades.id
  9.     AND clientes.tipo_cliente=tipos_cliente.id;

Lo que hemos hecho aquí es, en la clausula SELECT seleccionar los campos de los que queremos sacar información y darles un nombre de alias con AS. El alias nos sirve para utilizar nombres que nos aclaren más la función de la tabla en cuestión, pero es totalmente opcional en este caso.
Seguidamente, en la clausula FROM decimos de qué tablas sacamos la información del SELECT, y para acabar debemos aclarar las condiciones que se tienen que cumplir para que los valores sean los correctos en cada columna.
En este caso los id's de la tabla ppal (clientes) deben coincidir con los id's de las tablas relacionadas.
Si ejecutamos esta consulta debemos obtener el siguiente valor:

nombre_cliente localidad_cliente tipo_cliente
Marcos Gonzalez Oviedo Desarrollador
Daniel Aguilar Barcelona Desarrollador
Abel Molina Barcelona Diseñador
Ingeniería y Mezclas Girona Otros
Enlaces relacionados:
* JOIN Syntax

Update de la clase PHP ConsultaMysql

Mi amigo Marcos Gonzalez me ha pasado un nuevo método para la clase de peticiones MySQL comunes. El nuevo método transforma la query a formato XML y lo devuelve en utf-8.
Para ver el update ves al post original:

Enlace al post original:
* clase ConsultaMysql v.1.1

Clase PHP para tratar bases de datos MYSQL

* Nuevo método añadido para recibir la query en formato XML -> Última actualización 18/12/04 - descarga la última versión al final del post.

Aquí dejo una clase que hice hace tiempo para tratar bases de datos MYSQL.
Como extra lleva un par de métodos específicos para usar con Flash y uno para sacar info del server MYSQL de forma gráfica:

- result_par_valor_split() ( devuelve una cadena "Devuelve una cadena del tipo: id=1#2#5#3#4&title=Título 1#Título 2#Título 3# etc..." con los resultados de la consulta )
- result_par_valor_indx() Éste por Marcos Gonzalez ( Devuelve una cadena del tipo: "n_datos=5&id_0=1&title_0=Título 0&id_1=2&title_1=Título 2 etc..." )
- info () ( saca información de la consulta y del servidor MYSQL )

Además de lo fundamental:

- conectar ()
- escapar_chars () (añade contrabarras a los caracteres " ' \ )
- desescapar_chars () (la inversa del anterior)
- ejecutar_consulta () (ejecuta la cosulta en curso)
- result_num_filas () (devuelve el numero total de filas (horizontal) de la consulta)
- result_num_columnas () (devuelve el numero total de columnas (vertical) de la consulta)
- result_array_asoc () (devuelve un array asociativo de la consulta)
- cerrar_conexion () (cierra la conexión)

Aquí la clase:

PHP:
  1. <?php
  2.  
  3. /*
  4. * clase        ConsultaMysql
  5. * version    1.1
  6. * autor        Joan|Garnet http://www.joangarnet.com
  7. */
  8.  
  9.  
  10. class ConsultaMysql
  11. {
  12.     /////////////////////////
  13.     // PROPIEDADES PÚLICAS //
  14.     /////////////////////////
  15.  
  16.     var $servidor_mysql;    // direccion del servidor Mysql, normalmente es "localhost"
  17.     var $usuario;         // usuario del servidor Mysql
  18.     var $password;      // password del servidor Mysql
  19.     var $bbdd;        // nombre de la base de datos
  20.     var $consulta;      // aquí debes meter la consulta Mysql
  21.     var $separador;   /* si vas a usar el mdo result_par_valor_split(),
  22.                                 puedes asignar como separar los strings.
  23.                                 Por defecto se separan con "#"*/
  24.     var $testeando;   // true o false
  25.     var $email_admin;      /* si "$testeando" es false, entonces pon
  26.                                 el email del admin aqui para que reciba
  27.                                 notificaciones por email de los errores mysql */
  28.     var $resXML;            // para almacenar el resultado de la query en formato XML
  29.  
  30.     //////////////////////////
  31.     // PROPIEDADES PRIVADAS //
  32.     //////////////////////////
  33.  
  34.     var $conexion;
  35.     var $selec_bbdd;
  36.     var $string_sucio;
  37.     var $string_limpio;
  38.     var $resultado;
  39.     var $par_valor;
  40.     var $par_valor_split;
  41.     var $par_valor_indx;
  42.     var $largo_separador;
  43.     var $indice;
  44.     var $valor;
  45.     var $n_filas;
  46.     var $n_columnas;
  47.     var $fila;
  48.     var $arr_asoc;
  49.  
  50.  
  51.     /////////////////////////////
  52.     // CONSTRUCTOR DE LA CLASE //
  53.     /////////////////////////////
  54.  
  55.     function ConsultaMysql ()
  56.     {
  57.         $this->separador = "#";
  58.     }
  59.  
  60.     //////////////////////
  61.     // MÉTODOS PRIVADOS //
  62.     //////////////////////
  63.  
  64.     function err ()
  65.     {
  66.         if ($this-> testeando )
  67.         {
  68.             echo "<b><font color='red'>ERROR:</b> --> </b>" .
  69.             mysql_errno ()."</b> - <i>" .mysql_error ()."</i></font>";
  70.             exit ();
  71.         }
  72.         else
  73.         {
  74.             echo "<b><font color='red'>Ha habido un error</font></b>";
  75.             if ($this-> email_admin )
  76.             {
  77.                 echo ", el administrador ha sido informado por email";
  78.                 mail ($this-> email_admin ,
  79.                 "Error mysql en" .$_SERVER ['PHP_SELF'] ,
  80.                 "Error-> " .mysql_error ().
  81.                 "\n en->" .$_SERVER ['PHP_SELF'].$_SERVER ['QUERY_STRING'].
  82.                 "\n a las-> " .date ('H:i:s - D-d-m-Y'));
  83.             }
  84.             exit ();
  85.         }
  86.     }
  87.  
  88.     //////////////////////
  89.     // MÉTODOS PÚBLICOS //
  90.     //////////////////////
  91.  
  92.     function conectar ()
  93.     {
  94.         // conecta a la bbdd
  95.         $this-> conexion = @mysql_connect ($this-> servidor_mysql , $this-> usuario , $this-> password ) or $this-> err ();
  96.         $this-> selec_bbdd = @mysql_select_db ($this-> bbdd , $this-> conexion ) or $this-> err ();
  97.     }
  98.     function escapar_chars ()
  99.     {
  100.         // añade contrabarras a las palabras que lleven ' " \
  101.         $this-> string_limpio = addslashes ($this-> string_sucio );
  102.         return ($this-> string_limpio );
  103.     }
  104.     function desescapar_chars ()
  105.     {
  106.         // quita las contrabarras para mostrar el texto original con ' " \
  107.         $this-> string_limpio = stripslashes ($this-> string_sucio );
  108.         return ($this-> string_limpio );
  109.     }
  110.     function ejecutar_consulta ()
  111.     {
  112.         // ejecuta consulta Mysql
  113.         $this-> resultado = @mysql_query ($this-> consulta , $this-> conexion ) or $this-> err ($this-> resultado ) or $this-> err ();
  114.         return ($this-> resultado );
  115.     }
  116.     function result_num_filas ()
  117.     {
  118.         // devuelve el numero total de filas (horizontal) de la consulta
  119.         $this-> n_filas = mysql_num_rows ($this-> resultado );
  120.         return $this-> n_filas;
  121.     }
  122.     function result_num_columnas ()
  123.     {
  124.         // devuelve el numero total de columnas (vertical) de la consulta
  125.         $this-> n_columnas = mysql_num_fields ($this-> resultado );
  126.         return $this-> n_columnas;
  127.     }
  128.     function result_array_asoc ()
  129.     {
  130.         // devuelve un array asociativo de la consulta (por nombres de campo envez de por indice de campo)
  131.         while ($this-> fila = mysql_fetch_assoc ($this-> resultado ))
  132.         {
  133.             $this-> arr_asoc [] = $this-> fila;
  134.         }
  135.         return ($this-> arr_asoc );
  136.     }
  137.     function result_par_valor_split ()
  138.     {
  139.         // devuelve una cadena "var0=valor1,valor2,valor3&var1=valor1,valor2,valor3&var2= etc..." con los resultados de la consulta
  140.         $this-> result_array_asoc ();
  141.         $this-> par_valor = array ();
  142.         $this-> largo_separador = strlen ($this-> separador );
  143.         for ($k = 0; $k <sizeof ($this-> arr_asoc ); $k ++)
  144.         {
  145.             while ($this-> valor = current ($this-> arr_asoc [$k]) and $this-> indice = key (($this-> arr_asoc [$k])))
  146.             {
  147.                 if ( ! array_key_exists ($this-> indice , $this-> par_valor ))
  148.                 {
  149.                     $this-> par_valor [$this-> indice] = "";
  150.                 }
  151.                 $this-> par_valor [$this-> indice] .= $this-> valor .$this-> separador;
  152.                 next ($this-> arr_asoc [$k]);
  153.             }
  154.         }
  155.         foreach ($this-> par_valor as $indice => $valor )
  156.         {
  157.             $this-> par_valor_split .= $indice ."=" .$valor;
  158.             $this-> par_valor_split = substr ($this-> par_valor_split , 0, (strlen ($this-> par_valor_split ) - $this-> largo_separador ));
  159.             $this-> par_valor_split .= "&";
  160.         }
  161.         $this-> par_valor_split = substr ($this-> par_valor_split , 0, (strlen ($this-> par_valor_split ) - 1));
  162.         return (utf8_encode ($this-> par_valor_split));
  163.     }
  164.  
  165.  
  166.     //////////////////////////////////////
  167.     //                  //
  168.     //    método por Marcos Gonzalez   //
  169.     //    http://www.q-interactiva.com  //
  170.     //                  //
  171.     //////////////////////////////////////
  172.     function result_par_valor_indx ()
  173.     {
  174.         /*
  175.         RECIBE:
  176.         no recibe ningun parámetro ya que todos los que necesita los puede obtener
  177.         de la propia clase.
  178.         DEVUELVE:
  179.         Devuelve en la propiedad par_valor la respuesta a la consulta en formato
  180.         pares de variables valores indexados. Siempre a esta serie de parejas variable
  181.         valor indexadas, les precede una variable llamada n_datos que contiene el numero
  182.         de resultados obtenidos.
  183.         DESCRIPCION:
  184.         Obtiene en el numero de filas el numero de resultados obtenidos en la
  185.         consulta, y a su vez obtiene en el numero de columnas el numero de campos de los
  186.         resultados obtenidos. Posteriormente por cada respuesta (fila) concatena la cadena de
  187.         respuesta con un nuevo grupo de pares variable - valor indexadas con el indice de fila
  188.         del resultado.
  189.         */
  190.         $this-> result_num_filas ();
  191.         $this-> result_num_columnas ();
  192.         $this-> par_valor_indx = "n_datos=" .$this-> n_filas ."&";
  193.         $fil = $this-> result_array_asoc ($this-> resultado );
  194.         for ($i = 0 ; $i <$this-> n_filas ; $i ++)
  195.         {
  196.             foreach ($fil [$i] as $indice => $valor )
  197.             {
  198.                 $this-> par_valor_indx .= $indice ."_" .$i ."=" .$valor ."&";
  199.             }
  200.         }
  201.         $this-> par_valor_indx = substr ($this-> par_valor_indx , 0, (strlen ($this-> par_valor_indx ) - 1 ));
  202.         return (utf8_encode ($this-> par_valor_indx));
  203.     }
  204.  
  205.  
  206.     //////////////////////////////////////
  207.     //                  //
  208.     //    método por Marcos Gonzalez   //
  209.     //    http://www.q-interactiva.com  //
  210.     //                  //
  211.     //////////////////////////////////////
  212.     function result_XML()
  213.     {
  214.     /*
  215.     RECIBE: no recibe ningun parámetro ya que todos los que necesita los puede obtener
  216.     de la propia clase.
  217.     DEVUELVE: Devuelve en la propiedad resXML la respuesta a la consulta en formato
  218.     XML.
  219.     DESCRIPCION: Obtiene en el numero de filas el numero de resultados obtenidos en la
  220.     consulta, y a su vez obtiene en el numero de columnas el numero de campos de los
  221.     resultados obtenidos. Posteriormente por cada respuesta (fila) crea un nodo con sus
  222.     nodos anidados.
  223.     */
  224.         $this->result_num_filas();
  225.         $this->result_num_columnas();
  226.  
  227.         $this->resXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<datos>\n";
  228.  
  229.         $fil = $this->result_array_asoc ( $this->resultado );
  230.  
  231.         for ( $i=0 ; $i<$this->n_filas ; $i++ )
  232.         {
  233.                 $this->resXML .= "\t<dato>\n";
  234.                 foreach ( $fil[$i] as $indice=>$valor )
  235.                 {
  236.                          $this->resXML .= "\t\t<".$indice.">".$valor."</".$indice.">\n";
  237.  
  238.                 }
  239.                 $this->resXML .= "\t</dato>\n";
  240.         }
  241.  
  242.         $this->resXML.="</datos>";
  243.         return (utf8_encode($this->resXML));
  244.     }
  245.  
  246.  
  247.  
  248.     function cerrar_conexion ()
  249.     {
  250.         // cierra la conexion existente
  251.         mysql_close ($this-> conexion );
  252.     }
  253.     function info ()
  254.     {
  255.         // devuelve informacion de los campos de la tabla en la cosulta dada de forma grafica,
  256.         // la versión del server mysql y otros datos que pueden interesar acerca del estado del serviddor mysql
  257.         $this-> i = 0;
  258.         $this-> n_columnas = $this-> result_num_columnas ();
  259.         echo "<table cellpadding=3 border=1><tr>";
  260.         while ($this-> i <$this-> n_columnas )
  261.         {
  262.             echo"<td style='font-type:Arial;font-size:14px;'>" .
  263.             "<b style='color:green;'>nombre</b> " .mysql_field_name ($this-> resultado , $this-> i )."<br />" .
  264.             "<b style='color:green;'>tipo</b> " .mysql_field_type ($this-> resultado , $this-> i )."<br />" .
  265.             "<b style='color:green;'>longitud max</b> " .mysql_field_len ($this-> resultado , $this-> i )."<br />" .
  266.             "<b style='color:green;'>flags</b> " .mysql_field_flags ($this-> resultado , $this-> i )."<br />" .
  267.             "</td>";
  268.             $this-> i ++;
  269.         }
  270.         echo "</tr><tr><td colspan=" .$this-> i ." style='font-type:Arial;font-size:14px;'>";
  271.         echo "<b style='color:green;'>La informaciel server es la siguiente:</b><br />" .
  272.         "MySQL server version: " .mysql_get_server_info ();
  273.         echo "<br /><pre>";
  274.         print_r (explode ('  ' , mysql_stat ()));
  275.         echo "</pre>";
  276.         echo "</tr></table>";
  277.     }
  278. } // fin de la clase
  279.  
  280. ?>

Contador de visitas PHP para Movable Type

He hecho un sencillo sistema en PHP y Flash para poder llevar cuenta de las visitas por cada post en el blog.
Aquí dejo el código y una explicación de como instalarlo.
Los requisitos necesarios para poder hacerlo funcionar son que el servidor soporte PHP y que Movable Type esté montado en una base de datos Mysql.

1. Creación de la nueva tabla
Lo primero que tenemos que hacer es crear una nueva tabla en la base de datos del blog que nos permita llevar cuenta de las visitas por cada post. Para ello he adjuntado en el archivo a descargar un script .sql que nos creará la nueva tabla llamada mt_entry_visitor_count.

2. Entrada de las variables del archivo PHP
Editamos el archivo contador_visitas.php y cambiamos las variables necesarias:

PHP:
  1. // edita estas variables
  2. $server  = "localhost";
  3. $usuario    = "mi_usuario_base_datos";
  4. $password   = "mi_password_base_datos";
  5. $base_datos = "base_datos_movable_type";
  6. // fin edita estas variables

3. Subir los archivos
Una vez tenemos la tabla creada en la bbdd y el archivo php editado, subimos los dos archivos a la carpeta correspondiente
En mi caso tengo una carpeta llamada mt-static en a cual he creado una subcarpeta llamada backend. Ahí he subido los archivos contador.swf y contador_visitas.php
Si no lo tienes montado así, súbelos donde te parezca más indicado, pero que sea fuera del directorio cgi-bin.

4. Modificar los templates de Movable Type
Ahora que ya está todo listo toca modificar los templates para empezar el recuento y que se muestre el contador en cada post.
Vamos al panel de Movable Type en la parte de templates y editamos:

* En la parte Index Templates:
  - Main Index
* En la parte Archive-Related Templates:
  - Category Archive
  - Date-Based Archive
  - Individual Entry Archive

y agregamos en cada uno de ellos el código que incrusta el .swf del contador entre los tags <MTEntries> </MTEntries> cambiando el valor de los tags param name="movie" y embed src= por las urls correspondientes.
Por ejemplo yo lo tengo así:
En la parte donde aparece "Posteado por....." justo al final, que será después del tag </MTEntryIfAllowPings>

<p class="posted">
... blah blah
.... blah blah
.....<a href="<$MTEntryPermalink archive_type="Individual"$>#trackbacks">TrackBack</a>
</MTEntryIfAllowPings><br>

// empieza código para el contador de visitas
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="175" height="15" id="contador" align="middle">
<param name="allowScriptAccess" value="sameDomain" />
<param name="movie" value="http://www.joangarnet.com/mt-static/backend/contador.swf?entry_id=<$MTEntryID$>&url_base=http://www.joangarnet.com/mt-static/" />
<param name="quality" value="high" />
<param name="bgcolor" value="#f5f5f5" />
<embed src="http://www.joangarnet.com/mt-static/backend/contador.swf?entry_id=<$MTEntryID$>&url_base=http://www.joangarnet.com/mt-static/" quality="high" bgcolor="#f5f5f5" width="175" height="15" name="contador" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>
// fin código para el contador de visitas

</p>
</MTEntries>

La parte que se tiene que modificar sería exactamente:

<param name="movie" value="http://www.mi_dominio.com/tu_ruta_hasta_backend/backend/contador.swf?entry_id=<$MTEntryID$>&url_base=http://www.joangarnet.com/tu_ruta_hasta_backend/" />
<embed src="http://www.mi_dominio.com/tu_ruta_hasta_backend/backend/contador.swf?entry_id=<$MTEntryID$>&url_base=http://www.joangarnet.com/tu_ruta_hasta_backend/"