martes, 23 de marzo de 2010

Triggers en MySQL

A partir de MySQL 5.0.2 se incluyó soporte básico para triggers. Por ahora es muy básico y limitado, pero aún así es una importante feature. En este artículo voy a explicar que son los triggers y como se usan en MySQL.

Que son los triggers


Los triggers (disparadores en español) son acciones que pueden ejecutarse de manera automática cuando determinado evento ocurre en una tabla.

Al crear un trigger, se le asocia con una tabla, y se lo programa para que se active antes o después de la ejecución de que una sentencia del tipo INSERT, DELETE o UPDATE ocurra en esa tabla. Básicamente un trigger se compone de tres partes:


  • Evento


    Es el evento que tiene que ocurrir para que el trigger se active. Puede ser una sentencia INSERT, DELETE o UPDATE


  • Restricción


    Una vez activado el trigger, se puede evaluar una condición, para saber si ejecutarlo o no.


  • Acción


    La acción que realiza el trigger al ejecutarse.


Como se usan los triggers


Para crear un trigger se usa la sentencia CREATE TRIGGER, junto a cláusulas que le indican cuando activarse y que hacer cuando se active. Veamos un ejemplo:



Tenemos la tabla test, con los campos id, name y date. Vamos a crear un trigger para que cada vez que se inserte un registro en la tabla, se inserte automáticamente la fecha en el campo date.

[sourcecode language="sql"]DELIMITER //
CREATE TRIGGER set_date
BEFORE INSERT ON test
FOR EACH ROW BEGIN
SET NEW.date = NOW();
END;
//[/sourcecode]

NOTA: usamos la sentencia DELIMITER para poder usar “//” como delimitador en vez de “;”.

Veamos parte por parte que fue lo que hicimos:


  • CREATE TRIGGER set_date


    Creamos el trigger con la sentencia CREATE TRIGGER y lo nombramos como set_date.


  • BEFORE INSERT ON test


    Le dijimos que se ejecute antes (BEFORE) de que se ejecute una sentencia INSERT en la tabla test (INSERT ON test).


  • FOR EACH ROW BEGIN


    Comenzamos un bucle en el que le indicamos que hacer por cada vez que se active el trigger.


  • SET NEW.date = NOW();


    Le indicamos la acción a realizar al ejecutarse el trigger. En este caso, insertar en el campo date la fecha actual, con NEW.date nos estamos refiriendo al campo del registro que se va a insertar. Y con NOW() obtenemos la fecha actual.


Ahora cada vez que insertemos un nuevo registro en la tabla test, se va a insertar la fecha actual automáticamente en el campo date.

Si por alguna razón, quisiéramos que el trigger no se ejecute más, debemos eliminarlo. Para eliminar un trigger, se utiliza la sentencia DROP TRIGGER indicándole el nombre del trigger a borrar, en nuestro ejemplo sería algo así:

[sourcecode language="sql"]DROP TRIGGER set_date;[/sourcecode]

NOTA: no olvidar volver a poner el delimitador como “;”. (DELIMITER ;).

Un ejemplo un poco más interesante


Antes habíamos dicho que un trigger tiene tres partes: un evento, una restricción y una acción. En el ejemplo anterior teníamos el evento y la acción, pero no usamos ninguna restricción. Veamos otro ejemplo en el que usemos una restricción:

Tenemos una tabla employers, con los campos id, name y salary. Vamos a crear un trigger que verifique que el valor del campo salario sea siempre positivo.

Con este trigger nos aseguramos de que cada vez que se actualice un registro, el valor de salary siempre sea positivo.

[sourcecode language="sql"]DELIMITER //
CREATE TRIGGER positive_update
BEFORE UPDATE ON employers
FOR EACH ROW BEGIN
IF NEW.salary < 0
THEN SET NEW.salary=OLD.salary;
END IF;
END;
//[/sourcecode]

Los puntos importantes de esto serían:


  • IF NEW.salary < 0


    Con eso verificamos si el nuevo valor para el campo salary (NEW.salary) es menor a cero.


  • THEN SET NEW.salary=OLD.salary;


    Si la condición anterior se cumple, entonces el nuevo valor de salary va a ser igual al viejo valor de salary (OLD.salary).


Para insertar, hacemos un trigger parecido, pero si el valor de salary es menor a cero, entonces cambia el valor a cero:

[sourcecode language="sql"]DELIMITER //
CREATE TRIGGER positive_insert
BEFORE INSERT ON employers
FOR EACH ROW BEGIN
IF NEW.salary < 0
THEN SET NEW.salary=0;
END IF;
END;
//[/sourcecode]

NOTA: para que un usuario pueda crear triggers, necesita el privilegio SUPER.

Bueno, todavía es algo muy limitado el tema de los triggers en MySQL. Pueden consultar más sobre triggers en la info. oficial de MySQL sobre triggers.

LINK DE ARTÍCULO: AQUÍ

Nuevo, Sistema de Manejo de hoteles gratuito para Elastix

Aquí les dejo un link con este excelente post que colgarón en VoipToday con respecto a este modulo de hotelería para Elastix:

Clik Aquí

viernes, 19 de marzo de 2010

Tips para Programar en PHP (la funcion extract)

Bien pues puede que esta no sea la solucion a los problemas de todos los programadores del mundo, pero igual puede ser util para quien comienza a programar en este lenguaje, los lenguajes de script para desarrollo web, suelen tener muchas funciones que desconocemos y son de mucha utilidad, recientemente en una visita a puebla con un buen cuate, me toco ver como una persona a su cargo estaba realizando un formulario enorme y me refiero a enorme con mas de 40 campos en el dicho formulario, el objetivo era que ese formulario al ser procesado se enviara por correo a una cuenta determinada, hasta ese punto un tipico trabajo de una forma de contacto en internet, como para variar soy muy curioso (en ocasiones hasta metiche) en los asuntos de programacion, me toco ver que el formulario una vez enviado lo recibia un script de PHP y que lo que ellos estaban haciendo era incializar variables una por una desde el objeto $_POST para despues concatenarlas y pasarlas una funcion que enviara el mail, zaz me vinieron a la mente entre recuerdos de mis primeras clases de programacion y una obsesion que tengo con querer hacer las cosas mas simples pero a la vez faciles, despues de pegar el grito en el cielo por lo que estaban haciendo y preguntar si les podia dar un tip les dije que habia una manera de simplificar eso, de dibujar el formulario casi nadie se salva eso es inevitable pero de procesar las variables mas sencillo y usar un pequeño ciclo para concatenar era lo mas viable.
Primero les explique la susodicha funcion extract que segun la descripcion de la documentacion de PHP hace esto:
Descripción
void extract ( array $matriz_vars [, int $tipo_extraccion [, string $prefijo ]] )
Esta función se utiliza para importar variables desde una matriz a la tabla de símbolos actual. Toma la matriz asoiativa matriz_vars y trata las claves como nombres de variable y los valores como los valores de éstas. Para cada par clave/valor creará una variable en la tabla de símbolos actual, sujeto a los parámetros tipo_extraccion y prefijo .
Como vemos la definicion es algo mmmmmm…… indigerible pero si le buscamos un enfoque practico resulta sencilla veamos
Tenemos la situacion anteriormente descrita, en lugar de inicializar variables asi:

Se podria usar la funcion extract y resultaria mas facil:

Como ven la funcion extract toma el array $_POST donde vienen todos los valores del formulario y automaticamente las convierte y asigna sus valores a variables con el mismo nombre de las que venian del formulario, esto nos evita estar inicializando variables y perder tiempo valioso en la programacion, esta fue una de las utilidades que encontre en esta funcion y que en ese momento comparti con mi cuate.
Ademas como todo ejejej siempre hay muchos caminos para lograr el resultado final, me preguntaba y bueno que la concatenada de las variables no se podia hacer mas facil y le dije claro, solo que aqui en lugar de extract vamos a usar un pequeño truco con un bucle For Each, el resultado fue el siguiente:
$value){
$todaslasvariables.="$key - $value
";
}
echo $todaslasvariables;
?>
Que fue lo que paso aqui, sencillo tome el Array $_POST con todos sus valores y nombres, recorri con un ciclo en ocasiones poco explotado que es el Foreach y las concatene automaticamente en una sola variable, y listo ya teniamos una variable con todos los datos de campo y valor listos para ser enviados por correo.
Se que no es la quinta maravilla del mundo pero a como son utiles los tips cuando uno esta empezando a conocer un lenguaje, este se los comparto como en su momento un buen cuate y compañero lo hizo, el buen Omar Cobos desde su blog Pragmatic fue el que me dio a mi ese tip.
FUENTE: AQUÍ

Presentación: "Buenas Prácticas de Desarrollo en PHP"

Como en estos dias he vuelto a repasar algunos conceptos de PHP y formas nuevas de programación me puse a refrescar las buenas practicas de programación y encontre este artículo aquí, espero que les sea de utilidad

Hace un tiempo que vengo recomendando esta presentación como punto de partida para definir un estándar de desarrollo en una empresa. En ambientes Java no se discute quién define los estándares, es la empresa Sun y a nadie se le ocurriría inventar el suyo propio. Además, en el mundo Java existen estándares para todo, desde la codificación, forma de programar, etc.
LINK
php development best practices


En el lado opuesto del mundo estamos nosotros, los del "Mundo PHP", donde cada cual tiene su propio estándar y programa "como quiere" (con todos los problemas que esto acarrea). Para evitarlo, lo mejor que podemos hacer es seguir los lineamientos generales que se desprenden de los documentos de Zend.

Y esta es una buena presentación por donde empezar.

Camara Motorizada controlada desde Asterisk

Leyendo en Voiptoday halle un Post bastante curioso e interesante:

post on fenyo.net] For some years, I lodge different pets at home (Cat, Chinchilla, Hamsters).

Each time I tried to phone one of them, I was unable to understand what he said : I tried but never succeeded in teaching any human language to them. So, I created this motorized Camera controlled by the telephone, in order to supervise them when I'm at my office.

The system is made of 3 parts:
* 1- a private PBX based on Asterisk: this Linux PC is connected to the PSTN. When it receives a phone call, it converts DTMF signals to commands sent into an asynchronous V.24 interface (RS-232-C),

* 2- an electronic box based on a micro-controller that receives commands from a V.24 interface and is able to drive a motor (stepper),

KONICA MINOLTA DIGITAL CAMERA

* 3- an USB camera attached to the stepper, broadcasting to the Internet.



The command part of the box is based on a microcontroller (Microchip PIC16F876) connected to my personal PBX (PC running Asterisk) through a serial port (thanks to the well-known MAX232N, a +5V-powered RS-232 driver). The power part is made of a quadruple half-H driver (L293D from Texas Instruments) driven by 4 inverters packaged in a SN7416.
Here are the schematics:

clip_image002



















KONICA MINOLTA DIGITAL CAMERA


command part



KONICA MINOLTA DIGITAL CAMERA


power part
KONICA MINOLTA DIGITAL CAMERA

camera part
KONICA MINOLTA DIGITAL CAMERA

stepper part
KONICA MINOLTA DIGITAL CAMERA

SN476 + L293D both from Texas Instruments

What about the software parts ?

- The assembler code for the PIC is available here.
- In your PBX dial plan (Asterisk configuration file extensions.conf), you need to add the left and right actions (in this example, press 7 and 8 to let the camera rotate left and right):
; stepper
exten => 7,1,System(/bin/stepper-left-digium.sh)
exten => 7,n,Goto(s,begin)
exten => 8,1,System(/bin/stepper-right-digium.sh)
exten => 8,n,Goto(s,begin)
- These shell scripts call /bin/stepper (see stepper.c).

Watch it now!


Realmente si se tuviera el equipo valdría la pena probarlo

jueves, 18 de marzo de 2010

Creando Webs Modulares

En esta ocasión les traigo un excelente articulo que tome de ZonaPhp, el cual estoy seguro les ayudará a todos los que programamos, ya sea para enseñarnos o refrescarnos algunos conocimientos vitales a la hora de programar.

Después de embeber código PHP entre el HTML por un tiempo, cualquier principiante que esté en planes de dejar de serlo, ve cierto patrón que se repite y piensa... ¿No habrá otra manera mejor, más ordenada de hacer esto?. Pues si, si la hay. Y en este artículo aprenderemos una de estas maneras.

Lo habitual
Cuando aprendemos nuestros primeros pasos con PHP, cualquier tutorial o manual que leemos, nos enseña y vanagloria las bondades de poder incluir el código PHP directamente entre el HTML. Entonces, es muy habitual ver ejemplos del tipo:

PHP:



  1. <html>


  2. <head><title>Ejemplo de PHP embebido</title></head>


  3. <body>


  4. <?php


  5. echo "Este texto se hace con PHP";


  6. ?>


  7. </body>


  8. </html>



Y como la mente y el alma de un principiante de cualquier tema, está preparada para aprender todo lo que pueda, en el menor tiempo que pueda, toma este tipo de ejemplos como "verdades universales" y comenzamos a ver código PHP embebido entre el HTML por TODOS lados. Pero no hay que preocuparse, esto no es necesariamente malo, y todos lo hicimos en menor o mayor medida al comenzar. Es un paso necesario que hay que aprender a superar. :D

Luego de un tiempo, y después de haber leido un poco más, aprendemos que todas las partes comunes de código que son repetitivas, pueden residir en archivos separados y ser "Incluidas" en nuestro código con tan solo el uso de una función:



  1. <html>


  2. <head><title>Ejemplo de PHP embebido</title></head>


  3. <body>


  4. <? include('includes/header.php'); ?>


  5. <table>


  6. <tr>


  7. <td width="120"><? include('includes/menu.php'); ?></td>


  8. <td>Aqui va el contenido del sitio web propiamente dicho. Recordar que es terriblemente MALO y PERJUDICIAL para la salud de su sitio, utilizar archivos externos con extensión ".inc"</td>


  9. </tr>


  10. <? include('includes/footer.php'); ?>


  11. </table>


  12. </body>


  13. </html>



Entonces, ese es el momento en que include() se convierte en nuestro mejor amigo y descubrimos, fascinados, como podemos lograr una verdadera mejora en el mantenimiento de nuestros sitios, al tener que modificar 1 solo archivo y que este cambio, se vea reflejado en TODAS las páginas que incluyan ese archivo. Hemos, señoras y señores, alcanzado el Nirvana.

Pero, lamento decepcionarlos, ningún estado de felicidad suprema es permanente. Luego de un tiempo, y a medida que seguimos utilizando este método, de repente nos vamos dando cuenta que algo simplemente no cuadra. Si bien el anterior método del include() nos salvó en su debido momento, nos vamos dando cuenta que para crear una nueva página, es necesario repetir muchas veces los include() que llaman a las partes comunes de nuestro sitio. Esto sin contar que si, por arte de magia o capricho de un jefe/cliente, la cabecera de nuestro sitio pasa de ser header.php a cabecera.php, deberiamos modificar uno a uno todos los archivos que hagan un llamado a "header.php" y hacer el reemplazo.

Es en este punto, donde cientos de programadores, todos los años se hacen la misma pregunta: ¿No habrá una manera mejor de hacer esto?

Una Mejor Manera

Y si. Siempre existe una mejor manera de hacer las cosas. Y este caso no es la excepción.

Después de mucho pensar, y de mirar constantemente el código, una y mil veces, uno termina siempre preguntándose : ¿Y si hiciéramos las cosas al revés? ¿Qué pasaría si en vez de incluir todas las partes comunes de nuestro sitio (Header/Footer/etc), solamente incluyéramos el contenido?

Pero que buena pregunta! Veamos que sucedería.

La primera cuestión que nos llega a la mente, es que sería necesario indicarle a nuestro archivo.php, qué página queremos cargar. Veamos como podemos hacer esto :



  1. <?php


  2. // Leemos la variable que indica que página queremos cargar.


  3. if(empty($_GET['modulo']))


  4. $pagina='home.php';


  5. else


  6. $pagina=$_GET['modulo'];


  7. include('includes/header.php');


  8. include('modulos/'.$pagina);


  9. include('includes/footer.php');


  10. ?>



De esta manera, si llamáramos a este archivo index.php, para cargar algún "modulo" de nuestro sitio web, tan sólo deberíamos indicarlo en el URL, de esta manera : http://www.nuestrositio.com/index.php?modulo=foro.php.

Pero de este método se desprenden varias cuestiones, a saber:

  • Si un usuario "distraido" pusiera en la variable modulo un nombre de archivo inexistente, aparecería un mensaje de error (si PHP está configurado para mostrar errores, lo que es lo más común) indicando que el archivo no existe. Así que es necesario primero, identificar si el archivo que el usuario intenta acceder, existe.

  • Cuestiones de Diseño : Es muy posible, que no todos los "módulos" utilicen el mismo "diseño base" del sitio, o sea, que no siempre sea necesario mostrar la misma estructura, o el mismo sistema de navegación. Sería necesario de alguna manera, indicarle a nuestro sitio que "diseño base" utilizará cada módulo.

  • ÿltimo pero no menos importante, la Seguridad. Dejar al descubierto una variable que indica que archivo incluir, es una de las fallas de seguridad más serias que posee un sitio web. ¿Se imaginan que sucedería si un usuario, no ya tan "distraido" sino un poco más malicioso, llamara a nuestro sitio web de esta manera : http://www.nuestrositio.com/index.php?modulo=../../../../../etc/passwd ?
    Sirenas de Emergencia por todos lados !!! De esto se desprende que hay que encontrar una manera de controlar que la página que sea pedida, esté dentro de las opciones permitidas.


Vistas todas las desventajas de este primer acercamiento, veremos de que manera las podemos solucionar con un poco de ingenio y mucho PHP.

Modularizando nuestro sitio

Teniendo las consideraciones de seguridad y diseño en cuenta, vamos a desarrollar un sistema que nos permita modularizar nuestro sitio, manteniendo cierta flexibilidad para poder indicar que Diseño ( o Layout, como lo llamaremos en el código ) utilizarán nuestros módulos. Además, mantendremos un listado de todas las páginas que pueden ser invocadas, de manera que evitaremos que cualquier archivo de los que el Webserver tenga acceso de lectura, pueden terminar "sin querer" en el navegador de nuestro visitante.

Este listado podriamos guardarlo de diferentes maneras : archivos de texto con algún formato estandar o propio, en una Base de Datos, en un archivo XML (como es costumbre en algunas aplicaciones más complejas) o con tipos de datos propios del PHP (en este caso, arreglos). "Yo escogo este último porque me place, vosotros podéis escoger el tipo que queráis" (los fanáticos de Cha-Cha-Cha estarán esbozando una sonrisa). Y justifico mi decisión:

  • No tengo personalmente nada en contra de los archivos de texto plano, pero parsear los contenidos de uno, con el tipo de formato que sea, incluye cierta lógica de programación extra innecesaria, ya que la idea es hacer las cosas lo más sencillas posibles y no al revés.

  • Una base de datos definitivamente haría más sencillas las cosas, pero limitaría la utilidad de este método a aquellos servidores que no posean bases de datos. Se que los servidores que no poseen bases de datos hoy por hoy son escasos, pero prefiero no basarme en esa solución para hacer la aplicación lo más compatible posible.

  • Muchos ven en el formato XML al "santo grial" de las soluciones para almacenar datos o utilizarlos como sistemas de configuración. Y posiblemente para aplicaciones de escritorio esto no sea tan errado, ya que el archivo XML se parsea una vez y luego se mantienen sus datos en memoria durante toda la "vida" del programa. Pero en un ambiente web, sería necesario no solo que el PHP tenga activada alguna de las opciones para trabajar con XML, sino que se tendría que parsear el archivo XML ( con el gasto de recursos que esto conlleva ) una vez POR CADA pedido de página que se le hiciera el servidor. Definitivamente, NO. Aparte, es un tutorial para principiantes, asi que vamos a hacer las cosas sencillas.


Así es que para nuestro sistema de configuración, vamos a utilizar los viejos y queridos arreglos asociativos de PHP. El siguiente es un ejemplo básico para un sitio web realmente pequeño, pero ya veremos de extenderlo a medida que nuestro ejemplo "evolucione".

conf.php



  1. <?php


  2. /*


  3. * Archivo de configuración para nuestra aplicación modularizada.


  4. * Definimos valores por defecto y datos para cada uno de nuestros módulos.


  5. */


  6. define('MODULO_DEFECTO', 'home');


  7. define('LAYOUT_DEFECTO', 'layout_simple.php');


  8. define('MODULO_PATH', realpath('./modulos/'));


  9. define('LAYOUT_PATH', realpath('./layouts/'));


  10. $conf['home'] = array(


  11. 'archivo' => 'home.php',


  12. 'layout' => LAYOUT_DEFECTO );


  13. $conf['articulo'] = array(


  14. 'archivo' => 'art.php' );


  15. ?>



Aqui vemos, como en la primera parte de nuestro archivo, definimos algunas constantes que nos van a servir: MODULO_DEFECTO, indicando cuál de los módulos cargar si no se indicó ninguno, LAYOUT_DEFECTO que indica que "diseño" se utilizará por defecto en los módulos, MODULO_PATH y LAYOUT_PATH, indicando directorios en los cuales vamos a almacenar nuestros módulos y layouts. En el ejemplo, quedarán en dos directorios separados, pero podrían ser el mismo sin problema.

Aqui vemos, que tenemos dos "módulos" en nuestra aplicación; "home" y"articulo". Estos nombres de índices, son los que le vamos a pasar a nuestra variable modulo, indicando a que sección de nuestro sitio queremos acceder.

Como vemos, cada "sección" contiene ( o deberia indicar ) dos directivas:"archivo""layout". El primer valor es el nombre del archivo que efectivamente vamos a incluir, asociado con el nombre del indice del arreglo. Esto soluciona en gran parte el problema de seguridad que nombramos anteriormente, ya que no se indica directamente el nombre del archivo a incluir, sino que se indica a través de un nombre ficticio, un alias.

El segundo valor, layout, es el nombre del archivo que contiene el diseño "base" de la aplicación. Aqui tenemos dos opciones, indicar en el archivo de configuración el nombre del archivo de layout, o expresar, mediante la constante definida antes, que cierto módulo utiliza el layout por defecto ( esto ayuda a la claridad luego cuando se quiera revisar el archivo de configuración y se aconseja ). Como podemos ver en el módulo "articulo", en este caso no se indica ningun archivo de layout. Esto nosotros lo tomaremos como que al no indicarse, se desea utilizar el layout por defecto (Esta es una opción realmente buena para los programadores holgazanes como yo, que no quieren escribir grandes archivos de configuración).

Programando las bases

Ya tenemos listo nuestro archivo de configuración, que servirá como columna vertebral de nuestra nueva aplicación modularizable. Ahora veremos como lo utilizamos. Pero primero, veamos un poco como organizaremos nuestro árbol de directorios en nuestra nueva aplicación, para tener todo bien ordenado.

  • includes/

  • layouts/

  • modulos/

  • index.php


Así, vemos como tendremos un directorio para nuestros includes, uno para los módulos que componen nuestra aplicación y otro para los distintos layouts. Recordemos que ahora, nuestro archivo index.php será el único punto de entrada para nuestro sitio. Esto representa una ventaja ya que podemos colocar alli todas las tareas repetitivas (inicialización de variables, conexión a una base de datos, lectura de otros archivos de funciones o configuración, etc.). Otra de las ventajas es que ante 1 cambio que afectaría a todo el sitio web, solo hay que realizarlo en 1 solo archivo, solucionando alguno de los problemas que la metodología de varios archivos incluyendo partes comunes acarreaba.

Nuestro archivo index.php comienza de esta manera

index.php



  1. <?php


  2. // Primero incluimos el archivo de configuración


  3. include('conf.php');


  4. /** Verificamos que se haya escogido un modulo, sino


  5. * tomamos el valor por defecto de la configuración.


  6. * También debemos verificar que el valor que nos


  7. * pasaron, corresponde a un modulo que existe.


  8. */


  9. if (!empty($_GET['mod']))


  10. $modulo = $_GET['mod'];


  11. else


  12. $modulo = MODULO_DEFECTO;


  13. /** También debemos verificar que el valor que nos


  14. * pasaron, corresponde a un modulo que existe, caso


  15. * contrario, cargamos el modulo por defecto


  16. */


  17. if (empty($conf[$modulo]))


  18. $modulo = MODULO_DEFECTO;


  19. /** Ahora determinamos que archivo de Layout tendrá


  20. * este módulo, si no tiene ninguno asignado, utilizamos


  21. * el que viene por defecto


  22. */


  23. if (empty($conf[$modulo]['layout']))


  24. $conf[$modulo]['layout'] = LAYOUT_DEFECTO;


  25. ?>



Como bien explican los comentarios, lo que hacemos primero es incluir el archivo de configuración, sin él no podríamos saber si un módulo está permitido o no, y que Layouts utilizar. Luego, validamos que la variable "mod" contenga algo. De estar vacía o con un nombre de algún módulo inexistente (segundo if()), entonces hacemos que cargue el módulo por defecto, que está indicado en la constante MODULO_DEFECTO. Lo mismo hacemos para el Layout a cargar, si no está indicado en el archivo de configuración, tomamos por defecto el valor contenido en LAYOUT_DEFECTO. Continuamos con nuestro index.php

index.php



  1. <?php


  2. /** Aqui podemos colocar todos los comandos necesarios para


  3. * realizar las tareas que se deben repetir en cada recarga


  4. * del index.php - En el ejemplo, conexión a la base de datos.


  5. *


  6. * include('clases/class.DB.php');


  7. * $db = new DB();


  8. * $db->conectar();


  9. */


  10. /** Finalmente, cargamos el archivo de Layout que a su vez, se


  11. * encargará de incluir al módulo propiamente dicho. si el archivo


  12. * no existiera, cargamos directamente el módulo. También es un


  13. * buen lugar para incluir Headers y Footers comunes.


  14. */


  15. $path_layout = LAYOUT_PATH.'/'.$conf[$modulo]['layout'];


  16. $path_modulo = MODULO_PATH.'/'.$conf[$modulo]['archivo'];


  17. if (file_exists($path_layout))


  18. include( $path_layout );


  19. else


  20. if (file_exists( $path_modulo ))


  21. include( $path_modulo );


  22. else


  23. die('Error al cargar el módulo <b>'.$modulo.'</b>. No existe el archivo <b>'.$conf[$modulo]['archivo'].'</b>');


  24. ?>



Aqui vemos algo que comentábamos antes. Encerrado en comentarios, hay cierto código que podemos incluir en nuestro index.php que, al ser ahora el único punto de entrada a todas las páginas de nuestro sitio, será ejecutado para cada página. Ya no hay que repetirlo en todas las páginas PHP, tan solo se coloca en el index.php. Esto es bueno, porque mientras menos repetición de código haya, más sencillo de mantener es todo. Vemos alli como ejemplo, el código para incluir e instanciar algún objeto de conexión a base de datos, pero podría ser cualquier otro código que necesitemos ejecutar cada vez que se vea una página, como por ejemplo, algún Validador de Usuarios registrados o el código necesario para dar seguimiento a las sesiones de Usuario.

Finalmente, nuestro archivo verifica que el archivo de Layout que se quiere incluir, exista primero. De existir, entonces se incluye y ya veremos en un ejemplo, como nuestro archivo Layout debe incluir luego, al archivo del módulo. Si no existiera el archivo de Layout, se intenta incluir directamente el archivo del módulo que se pidió, sin Layout, y si éste archivo tampoco existiera ( ¿demasiadas cosas que salen mal, no? ) entonces se muestra un error en la pantalla, indicando el nombre del módulo y el archivo que no se pudo hallar.

Perfecto, ya tenemos todo listo para cargar los módulos que necesitemos. Ahora, veamos como será un módulo de ejemplo y su archivo de Layut.

Tenemos dos opciones a la hora de crear un archivo de layout. Son las siguientes:

  • Incluir Headers y Footers comunes a todas las páginas dentro del index.php, ANTES y DESPUES de incluir el archivo de Layout, en el que dejaremos solo el diseño propio de la página para que albergue al módulo. Esto es útil en el caso de que un archivo de Layout no se encuentre o no sea necesario, y al incluir el Módulo, ya esté cargado el Header y luego sea incluido el Footer.

  • Hacer que el archivo de Layout, aparte de incluir el archivo del Módulo, sea el encargado de incluir Headers y Footers, lo cuál puede ser útil si el diseño general de varias secciones del sitio cambia drásticamente, como distintas subsecciones con Headers y Footers diferentes, o en el caso de "Versiones para Imprimir" o la creación de versiones en PDF de ciertos artículos.


Yo voy a elegir en este caso la segunda opción. Haré que el archivo de Layout'layout_simple.php' (el Layout por defecto, según el archivo dFe configuración) sea el encargado de incluir los archivos que hacen de Header y ooter en la aplicación. Esto es preferible a la primera opción ya que si, por ejemplo, queremos que un módulo específico de nuestra aplicación, devuelva un archivo .GIF como resultado ( utilizando GD ), entonces de esta manera, podremos indicar para ESE módulo, un archivo de Layout que se encargue de enviar los Headers correctos y luego incluir el archivo del módulo. Pero no se preocupen por estas consideraciones, ahora, veamos un ejemplo de Layout, que guardaremos en el directorio /layouts:

layout_simple.php



  1. <html>


  2. <head>


  3. <title>Tu Sitio Modular</title>


  4. </head>


  5. <body bgcolor="#9999cc">


  6. <basefont color="white" face="Verdana" />


  7. <?php include('includes/header.html'); ?>


  8. <table width="100%" border="0" cellspacing="1"cellpadding="1">


  9. <tr>


  10. <td width="140" bgcolor="#5b69a6"> </td>


  11. <td>


  12. <?


  13. if (file_exists( $path_modulo )) include($path_modulo );


  14. else die('Error al cargar el módulo <b>'.$modulo.'. No


  15. existe el archivo <b>'.$conf[$modulo]['archivo'].'</b>');


  16. ?>


  17. </td>


  18. </tr>


  19. </table>


  20. <?php include('includes/footer.html'); ?>


  21. </body>


  22. </html>



Ven? es un simple archivo HTML con la estructura básica de las páginas de nuestro sitio, incluyendo el Header, el Footer y el código necesario para llamar al módulo pedido por el usuario. Por favor noten el uso de la variable$path_modulo, para indicarle al Layout el nombre del módulo que queremos cargar, variable creada en el index.php y propagada al archivo de Layout por estar éste, incluido en el primero.

Entonces, ya tenemos nuestro index.php, tenemos el Layout que se encarga de incluir el módulo... ¿Qué nos falta? ¡Pues el módulo! ÿstos pueden ser tan complejos o tan simples como el usuario quiera. En el ejemplo siguiente, un módulo "home" bien simple, que se carga por defecto en nuestra aplicación :

home.php



  1. <h3>Bienvenido al Home</h3>


  2. <p>Este es un ejemplo de un sitio modular, como vemos, las páginas que


  3. componen los módulos, pueden ser tanto archivos.php como archivos.html,


  4. todo dependiendo de si necesitamos interactividad o no con el Servidor.


  5. La hora actual es : <b><?=date("H:m:s");?></b></p>


  6. <p>Para ver el contenido de un artículo, por favor, seguir el


  7. <a href="?mod=articulo">siguiente link</a>.</p>



De nuevo, un poco de HTML por aquí, un poco de PHP por allá. Cabe notar, eso si, la manera en la que hicimos un link hacia OTRA página de nuestro sitio: "?mod=articulo". Con esto, le indicamos al navegador, que queremos cargar el mismo archivo que tenemos actualmente, solo que con este nuevo "querystring". Si la página actual fuera algo como:

http://localhost/modulares/index.php

Indicando un link como recién, al hacerle click cambiaría a :

http://localhost/modulares/index.php?mod=articulo

O sea, queremos cargar OTRO módulo, esta vez llamado "articulo". Como ya todo el trabajo árduo está hecho, solo tenemos que crear un archivo llamadoart.php (ya que así lo indica el archivo de configuración) en el directorio/modulos/.

art.php



  1. <h3>Título del Artículo</h3>


  2. <p>Aqui tenemos el ejemplo de un artículo cargado en nuestra Web Modularizada.


  3. En este ejemplo simple, el artículo o nota, está escrito en HTML directamente,


  4. pero podría estar siendo sacado de la base de datos si quisiéramos, no tenemos


  5. limitación al respecto.</p>


  6. <p><a href="?mod=imp_art" target="_blank">Versión para Imprimir</a> |


  7. <a href="?mod=home">Volver al Home</a>.</p>



Así vemos, como crear un nuevo módulo es tan sencillo como crear el archivo pertinente, dejarlo en el directorios de Módulos, y actualizar el archivo de configuración para que permita accederlo. ÿste módulo, al no indicarse que Layout utiliza, vemos como toma el Layout por Defecto, o sea, el mismo que el Home. Cómo último paso, al final del artículo, tenemos dos links, uno, que nos regresa al Home del Sitio y el otro, el que nos interesa ahora, que ofrece una "Versión para Imprimir" del artículo. Modifiquemos nuestro archivo de configuración y agreguemos un nuevo módulo, que nos permita ofrecer una versión "Imprimible" del Artículo. Luego de editarlo, quedaría asi :

conf.php



  1. <?php


  2. /*


  3. * Archivo de configuración para nuestra aplicación modularizada.


  4. * Definimos valores por defecto y datos para cada uno de nuestros módulos.


  5. */


  6. define('MODULO_DEFECTO', 'home');


  7. define('LAYOUT_DEFECTO', 'layout_simple.php');


  8. define('MODULO_PATH', realpath('./modulos/'));


  9. define('LAYOUT_PATH', realpath('./layouts/'));


  10. $conf['home'] = array(


  11. 'archivo' => 'home.php',


  12. 'layout' => LAYOUT_DEFECTO );


  13. $conf['articulo'] = array(


  14. 'archivo' => 'art.php' );


  15. $conf['imp_art'] = array(


  16. 'archivo' => $conf['articulo']['archivo'],


  17. 'layout' => 'imprimir.php' );


  18. ?>



¿Llamamos al mismo módulo? Así es. Pero la sutil diferencia es que lo incluimos con un Layout distinto, más limpio, apto para salir por impresora. Aqui un ejemplo de este Layout, que utiliza Cascading Style Sheets :

imprimir.php



  1. <?


  2. $uri ="http://".$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];


  3. ?>


  4. <html>


  5. <head>


  6. <title>Versión para Imprimir</title>


  7. </head>


  8. <style type="text/css">


  9. .imprimir {


  10. margin: 3%;


  11. border: 2px solid black;


  12. padding: 2%;


  13. }


  14. #pie {


  15. font-size: 8pt;


  16. }


  17. </style>


  18. <body>


  19. <div class="imprimir">


  20. <?


  21. if (file_exists( $path_modulo )) include($path_modulo );


  22. else die('Error al cargar el módulo <b>'.$modulo.'. No existe el archivo <b>'.$conf[$modulo]['archivo'].'</b>');


  23. ?>


  24. <i id="pie">Este artículo se puede encontrar en : <a href="<?=$uri?>"><?=$uri?></a></i>


  25. </div>


  26. </body>


  27. </html>



Finalizando

Ya finalizando con este artículo, logramos tener una aplicación web que posee la capacidad de cargar distintos módulos y diseños dependiendo de los parámetros recibidos. Esto se parece mucho a un Patrón de Diseño llamadoFront Controller. Para los curiosos, ahi tienen dos links en los que Google les puede enseñar un par de cositas.

Hoy aprendimos como centralizar el funcionamiento de un sitio a través de un archivo de configuración. También como modularizar nuestro sitio web con la ventaja de poder aplicar distintos diseños a los diferentes módulos que lo componen. Y sobre todo, a hacerlo de una manera sencilla, eficiente y segura. ¿Qué más se puede pedir?

Bueno, un montón de cosas, estas son las que se me ocurren en este momento. Estoy seguro que a Uds. se les ocurrirán muchas más :

  • Podríamos incluir en el Layout por Defecto, un menú de opciones en la celda izquierda, de manera de facilitar la navegación del sitio.

  • Una modificación interesante, sería que al pedir un usuario, un módulo inexistente en el arch. de configuración, se cargara un módulo determinado ( y no el “home” ) indicando el error y mostrando una página “símil” ERROR 404.

  • Se podría agregar en el arch. de configuración, un dato más para cada módulo, que indique el título de la página. Y que el Layout se encargue de utilizar ese valor dentro del tag .

  • Recomendable sería que tanto los directorios de Layouts, Includes y Modulos, no estén disponibles en el mismo nivel que el Directorio DocumentRoot del WebServer, ya que de esa manera, por quien conozca el árbol de directorios, podría ejecutar los archivos llamándolos directamente. Para evitar esto, podemos tanto mover los directorios un nivel hacia arriba y modificar el archivo de configuración para que encuentre estos directorios ( y como vemos, no tendriamos que tocar nada en el código de la aplicación ) o bien utilizar algún método para proteger esos directorios por contraseña, como puede ser un archivo .htaccess de Apache.

  • Tener un solo punto de entrada en nuestro sitio web, implica el paso de varios parámetros a un solo archivo de nuestro sitio. Lo que hace que nuestras chances de ser indexados por un buscador tipo Google se vean reducidas. Pero para esto hay varias soluciones, y bien lo explica nuestro amigo Nok en Optimizando las URLs para las búsquedas.


Para los poco pacientes ( y para el resto también ) que no quieran estar copiando y pegando el contenido de estos ejemplos en los archivos, aqui les dejo un archivo ZIP con todos los archivos del artículo. Recuerden, no es código apto para producción, si quieren utilizarlo directamente en sus sitios Web, lo hacen bajo su propia responsabilidad. ¡No digan que no les avisé! ;)

Esto ha sido todo por este momento, espero que lo que hayan leido en este artículo les sea deutilidad en sus sitios web y les ayude a programar menos y más rápidamente

En lo personal me gusto mucho el artículo, además trataré de colgar mas artículos con respecto a lo que es programación estandares y más. Una vez más mis agradecimientos a zona PHP.

martes, 16 de marzo de 2010

Instalar eSpeak para Asterisk

Esta herramienta es parecida a flite pruebenla

Primero las dependencias:

  • Asterisk 1.6.x header files

  • eSpeak libraries and header files

  • libsndfile libraries and header files

  • libresample libraries and header files


aptitude install espeak espeak-data libespeak-dev libsndfile1 libsndfile1-dev

Esta ultima la podemos instalar en debian del siguiente repositorio:

deb http://ftp.de.debian.org/debian squeeze main

Hacemos un aptitude update y listo

aptitude install  libresample1  libresample1-dev

y listo, bajamos el archivo fuente:

wget http://cloud.github.com/downloads/zaf/Asterisk-eSpeak/Asterisk-eSpeak-1.6-0.1.tar.gz

tar -zxvf Asterisk-eSpeak-1.6-0.1.tar.gz

cd Asterisk-eSpeak-1.6-0.1

make && make install && make samples

y listo, solo reiniciamos el Asterisk y agregamos a nuestro dialplan algo como esto:

;eSpeak Demo

exten => 1234,1,Answer()

;;Play mesage using default language as set in espeak.conf

exten => 1234,n,Espeak("This is a simple espeak test in english.",any)

;;Play message in Spanish

exten => 1234,n,Espeak("Esta es una simple prueba espeak en español.",any,es)

;;Play message in Greek

exten => 1234,n,Espeak("???? ????? ??? ???? ???? ??? espeak ??? ????????.",any,el)

;;Read a text file from disk (relative to the channel language)

;;and play it with espeak using the asterisk channel language.

exten => 1234,n,ReadFile(MYTEXT=/path/${LANGUAGE}/myfile,200)

exten => 1234,n,Espeak("${MYTEXY}",any,${LANGUAGE})

exten => 1234,n,Hangup()

Pruebenlo y jueguen con el comando