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

Instalar Flite para Asterisk

Instalando festival noté un par de errores que luego corregiré en el post anterior, pero note que en voip-info.org mencionan una aplicación que funciona como un festival-lite y es Flite, aquí les dejó el comentario en ingles:

Flite (festival-lite) is a small, fast run-time synthesis engine developed at CMU and primarily designed for small embedded machines and/or large servers. Flite is designed as an alternative synthesis engine to Festival for voices built using the FestVox suite of voice building tools.
asterisk-flite is a Flite text-to-speech module for the Asterisk open-source PBX. This provides the "Flite" dialplan application, which allows you to use the Flite TTS Engine with Asterisk. It invokes the Flite TTS engine locally via the Flite C API, and uses it to render text to speech.

Su instalación es muy sencilla, en debian hacemos:

aptitude install flite flite-dev

Ahora debemos bajar el plugin para Asterisk:
wget http://cloud.github.com/downloads/zaf/Asterisk-Flite/Asterisk-Flite-1.6-0.1-beta2.tar.gz

lo descomprimimos:

tar -zxvf Asterisk-Flite-1.6-0.1-beta2.tar.gz

cd Asterisk-Flite

make && make install && make samples

Nota: las unicas dependencias que tiene este plugin son:


  • Asterisk 1.6.x header files

  • Flite libraries and header



Ahora solo falta reiniciar el Asterisk: /etc/init.d/asterisk restart

Editamos el extensions.conf  y ponemos algo como esto:

exten => 1234,1,Answer()
exten => 1234,n,Flite("This is a simple F lite test in english.",any)
;Read a text file from disk and pass it to flite
exten => 1234,n,ReadFile(MYTEXT=/path/myfile,200)
exten => 1234,n,Flite("${MYTEXT}",any)
exten => 1234,n,Hangup()


Eso sería todo lo probe y no me dió ningún problema la verdad, mas noche veré si se puede poner en español.

Saludos espero que les sirva de mucho, esto lo podemos mezclar con Bases de Datos y AGI.

Instalar Festival para que trabaje con Asterisk

En este ocasión les mostraré como instalar y configurar Festival para que trabaje con Asterisk, así podriamos hacer aplicaciones mezclando AGI con Festival y unas Base de Datos.

Para que Festival se integre en asterisk, antes de compilar la centralita tenemos que instalar dos paquetes:
sudo apt-get install festival festival-dev

#instalamos los parlantes en español e ingles

sudo apt-get install festvox-ellpc11k festvox-kallpc16k festvox-kallpc8k festvox-kdlpc8k

para averiguar que el modulo de festival esté correctamente cargado en asterisk, desde la consola de la centralita:

asterisk -rvvvvvvvvvvvvvvv

CLI> module unload app_festival

== Unregistered application 'Festival'

CLI> module load app_festival

== Parsing '/etc/asterisk/festival.conf':   == Found

== Registered application 'Festival'

Loaded app_festival => (Simple Festival Interface)

Si aparece algún tipo de error significa que el modulo no ha sido compilado y tenemos que volver a la compilación de Asterisk.

Festival viene con predefinido el idioma ingles. Para agregarle el idioma español hay que seguir estos pasos:

cd /usr/share/festival/voices

wget http://www.voztovoice.org/tmp/festival-spanish.zip

unzip festival-spanish.zip

Ahora modificamos el archivo de configuración de festival

vim /usr/share/festival/festival.scm

añadimos estas líneas

;(language__spanish)

(set! voice_default 'voice_el_diphone)

(define (tts_textasterisk string mode)

"(tts_textasterisk STRING MODE)

Apply tts to STRING. This function is specifically designed for

use in server mode so a single function call may synthesize the string.

This function name may be added to the server safe functions."

(let ((wholeutt (utt.synth (eval (list 'Utterance 'Text string)))))

(utt.wave.resample wholeutt 8000)

(utt.wave.rescale wholeutt 5)

(utt.send.wave.client wholeutt)))

Guardamos el archivo y modificamos el archivo de configuración de festival en asterisk:

vim /etc/asterisk/festival.conf

Estas son la líneas que hay que modificar/activar

[general]

host=localhost

port=1314

festivalcommand=(tts_textasterisk "%s" 'file)(quit)\n

Guardamos el archivo

Reiniciamos asterisk

/etc/init.d/asterisk reload

Para arrancar el servidor de Festival en automático ponemos esta línea en el archivo rc.local

vim /etc/rc.local

/usr/bin/festival --server

Ahora reiniciamos el servidor linux

reboot

Controlamos que el servidor festival esté corriendo:

Ahora vamos a añadir unas cuantas líneas en extensions.conf

vim /etc/asterisk/extensions.conf

exten => 650,1,Answer()

exten => 650,n,Festival(Asterisk y Festival trabajan junto. Chevere!!!)

exten => 650,n,Hangup()

Actualizamos el dialplan desde la consola

asterisk -rvvvvvvvvvvvvvvvvv

CLI> dialplan reload

Para que Festival se integre en asterisk, antes de compilar la centralita tenemos que instalar dos paquetes:
sudo apt-get install festival festival-dev#instalamos los parlantes en español e inglessudo apt-get install festvox-ellpc11k festvox-kallpc16k festvox-kallpc8k festvox-kdlpc8k

para averiguar que el modulo de festival esté correctamente cargado en asterisk, desde la consola de la centralita:
asterisk -rvvvvvvvvvvvvvvv
CLI> module unload app_festival   == Unregistered application 'Festival'
CLI> module load app_festival  == Parsing '/etc/asterisk/festival.conf':   == Found == Registered application 'Festival' Loaded app_festival => (Simple Festival Interface)
Si aparece algún tipo de error significa que el modulo no ha sido compilado y tenemos que volver a la compilación de Asterisk.
Festival viene con predefinido el idioma ingles. Para agregarle el idioma español hay que seguir estos pasos:cd /usr/share/festival/voices
wget http://www.voztovoice.org/tmp/festival-spanish.zipunzip festival-spanish.zipAhora modificamos el archivo de configuración de festivalvim /usr/share/festival/festival.scm
añadimos estas líneas
;(language__spanish) (set! voice_default 'voice_el_diphone)
(define (tts_textasterisk string mode)    "(tts_textasterisk STRING MODE)    Apply tts to STRING. This function is specifically designed for    use in server mode so a single function call may synthesize the string.    This function name may be added to the server safe functions."    (let ((wholeutt (utt.synth (eval (list 'Utterance 'Text string)))))    (utt.wave.resample wholeutt 8000)    (utt.wave.rescale wholeutt 5)    (utt.send.wave.client wholeutt)))
Guardamos el archivo y modificamos el archivo de configuración de festival en asterisk:

vim /etc/asterisk/festival.conf
Estas son la líneas que hay que modificar/activar
[general] host=localhost port=1314 festivalcommand=(tts_textasterisk "%s" 'file)(quit)\n
Guardamos el archivo
Reiniciamos asterisk
/etc/init.d/asterisk reload
Para arrancar el servidor de Festival en automático ponemos esta línea en el archivo rc.local
vim /etc/rc.local
/usr/bin/festival --server
Ahora reiniciamos el servidor linux
reboot
Controlamos que el servidor festival esté corriendo:

Ahora vamos a añadir unas cuantas líneas en extensions.conf

vim /etc/asterisk/extensions.conf
exten => 650,1,Answer() exten => 650,n,Festival(Asterisk y Festival trabajan junto. Chevere!!!) exten => 650,n,Hangup()
Actualizamos el dialplan desde la consola
asterisk -rvvvvvvvvvvvvvvvvv
CLI> dialplan reload

lunes, 15 de marzo de 2010

Asterisk AGI y Fast AGI

En estos dias he estado leyendome un libro de Asterisk, se trata de Asterisk AGI(Asterisk Gateway Interface), salen diez reglas que se deben tener en cuenta a la hora de programar AGI, haré un breve resumen de estas diez asi como de algunos puntos que me parecieron importantes, al final del post dejaré algunos links donde podrán ahondar más en el tema, ahora manos a la obra que ya me dió sueño jaja, ojo todo esta ingles espero que entiendan

How does AGI work:



As the previous diagram illustrates, an AGI script communicates with Asteriskvia two standard data streams—STDIN (Standard Input) and STDOUT (StandardOutput). From the AGI script point-of-view, any input coming in from Asteriskwould be considered STDIN, while output to Asterisk would be consideredas STDOUT.The idea of using STDIN/STDOUT data streams with applications isn't a new one,even if you're a junior level programmer. Think of it as regarding any input fromAsterisk with a read directive and outputting to Asterisk with a print or echodirective. When thinking about it in such a simplistic manner, it is clear that AGIscripts can be written in any scripting or programming language, ranging fromBASH scripting, through PERL/PHP scripting, to even writing C/C++ programs toperform the same task.



FastAGI Frameworks



AGI Frameworks




The AGI execution flow

Once an AGI script has been invoked, a preset information flow is performed between the AGI script and Asterisk. It is imperative to understand this information flow, as the structure of your AGI script depends on this flow. The following diagram describes the steps that occur when an AGI script is executed from within the Asterisk dialplan:



The ten rules of AGI development

Developers, who are given the task of developing an AGI script for the first time, tend to superimpose their traditional development techniques over the development of AGI scripts. By far, this is the most dangerous thing that can be done, as AGI scripting and traditional programming vary immensely. The following section will list the do's and don'ts that need to be followed, so that your AGI scripts work and function properly.

Rule #1: An AGI script should terminate as fast as possible

First-time AGI developers tend to develop their entire application within an AGI script. As you develop your entire application within an AGI script, you may gain the power of the scripting language, but will incur a cost of performance. Always make sure that the AGI scripts that you develop terminate their execution as fast as possible, returning to the dialplan as fast as possible. This concept dictates that each AGI script being run should behave quickly as an atomic unit—hence the name "Atomic AGI".
Rule #2: Blocking applications have no place in AGI

As a direct continuation to rule #1, you should never execute a blocking application from within an AGI script. Initiating a blocking application from within an AGI script will make your Asterisk environment explode slowly. Why is that? Because for every blocking application that you run from within the AGI script, you will have both your AGI script and the blocking application running for the duration of the lock. Imagine that you were to initiate the Dial application from within an AGI script, and the call created would last over thirty minutes. For those thirty minutes, your AGI script is still active. This isn't much of a problem when dealing with small-scale systems. But when trying to run 50 concurrent scripts, be prepared for failure. Blocking applications include the following: Dial, MeetMe, MusicOnHold, Playback (when dealing with long playbacks), Monitor, ChanSpy, and other applications that have an unknown execution duration.

Rule #3: Asterisk channels are stateful—use them

An Asterisk channel, once operational, is like a big bucket of information. Channel variables can be used to carry information from your AGI script to the dialplan and back. The variables remain as part of the channel untill the channel is terminated, when memory is then freed. Using this "bucket" enables you to carry variables and information obtained via an AGI script and then pass these to an application in the dialplan. For example, imagine that you are developing a pre-paid platform. A decision on the call timeout is taken via an AGI script. However, the actual dialling of the call is performed from the dialplan itself.

Rule #4: AGI scripts should manipulate data—no more

Most developers tend to think of AGI scripting as a functional unit, meaning that they enclose multiple functionalities into the AGI script. While AGI is fully capable of performing telephony functionality, it is best to leave this functionality to the dialplan. Utilize your AGI script to set and reset channel variables and communicate with out-of-band information systems. The concept of allowing out-of-band information flow into Asterisk's operational flow of channel, enables new functionality and possibilities. Not all logic should be handled by your AGI script. Sometimes, it is better to use the AGI script as a data conduit, while letting an external information system handle the data manipulation.

Rule #5: VM based languages are bad for AGI scripting

Virtual machine based programming languages' are bad for AGI scripting. Putting aside the rules #1 and #2, imagine that your application is built using an AGI script using the Java programming language. If you are familiar with Java, you most probably know that for each program that you execute using Java, a full Java virtual machine is invoked.

While this practice may seem fairly normal for information systems, Asterisk and IVR development vary. Imagine that our system is required to handle a maximum number of 120 concurrent channels, which means that the maximum number of concurrent AGI scripts will be 120. According to this concept, our Java environment will be fully invoked for each of these 120 instances. In other words, too many resources are being used just for the VM. If you really feel that you want to develop AGI scripts using Java, FastAGI is the way to go for you.

Rule #6: Binary-compiled AGI is not always the answer

While evaluating rules #1, #2 and #5, we can't but reach an almost immediate conclusion that we need to have our AGI script binary compiled. While in terms of efficiency and performance, a binary compiled AGI may provide better performance, the time required to develop it may be longer. In some cases, scripting languages such as PHP, PERL, and Python may provide near-similar performance at a lesser cost.

Also, when using binary compiled AGI scripts, you are always in charge of the memory allocation and cleanup. Even the most experienced developer can commit errors while dealing with memory allocation, so binary compiled AGI need not be the solution always.

If your system truly requires the performance edge of a binary compiled AGI, we encourage you to develop a prototype using a scripting language. Once you have your prototype working, start developing your binary version.

Rule #7: Balance your scripts with dialplan logic

While evaluating rules #1, #2 and #4, we must keep in mind that developing IVR systems with Asterisk resembles a high-wire balancing act. The fine art of balancing your dialplan with AGI scripts proves to be a powerful tool, especially when developing complex IVR systems.

Many developers tend to externalize functionality from the dialplan into AGI, while the same functionality can be achieved by writing dialplan macros or dialplan contexts. Using Asterisk's branching commands (goto, gotoif, exec, execif, gosub and gosubif) can easily remove redundant AGI code, passing the control from the AGI back to the dialplan.

Rule #8: Balance your scripts with web services

When evaluating rule #4, one may ask: "What is an out-of-band information system?" We shall explain now. Most Asterisk developers tend to develop their systems with the data information system—either embedded into their Asterisk server or communicating with an information system installed on the same server with the Asterisk server.

While, for small systems, this proves to be both efficient and economic, when developing a high-end ystem that requires scalability and redundancy, this methodology proves to be counter-productive. One of the methodologies (although many others exist) for interconnecting Asterisk with an out-of-band information system is web services. Communication to the web service is performed via AGI; the web-service protocol—you can use your favourite one. The choice of protocol isn't that important, as almost any protocol type used for web services would do. Be it SOAP, WSDL, XML-RPC, WDDX or any other, take your pick, and the performance and scalability should be similar in any of these.

Rule #9: Syslog is your friend—use it

Every developer knows that using log files for debugging and monitoring purposes is a must. Be it for using a binary compiled AGI or a scripting language based AGI, make sure to utilize the logging facility. Trying to debug an AGI application from within the Asterisk console, though possible, can prove to be a tedious task. Sending log entries to a well-formatted log can save you much time and headache.

Scripting languages, such as PHP and PERL, do not offer a direct debugging facility, making the debugging of such AGI scripts even harder. Using log files as a debugging point for your AGI script will prove very useful when developing highly complex systems.

In order to make your syslog more readable, assign a self-created unique ID to each of your calls. When writing to your log, make sure that the unique ID appears in each log entry, so that you can trace a specific

session flow through Asterisk. Remember, an Asterisk channel is stateful. The unique ID will remain as part of the channel untill it is removed from the system.

Rule #10: The Internet is for Asterisk

As bad as the following may sound, if you have a problem or an idea, remember that someone else had almost definitely come across it before you did. I don't want to discourage you, but actually, I want you to make use of the multitude of Asterisk resources available on the Internet.

Básicamente esa seria toda la informaicón hasta ahora, aquí les dejo los links:

Nuevo Libro publicado sobre Elastix PBX en castellano.

Durante el fin de semana pasado, en la ciudad de Guayaquil, Ecuador, fue presentado el nuevo Libro de Alfio Muñoz sobre una de las mas populares distribuciones basadas en Asterisk que tanto conocemos…Elastix

En dicho libro realizado integramente por Alfio Muñoz, conocido Instructor, partner y colaborador del proyecto que cuenta además con apoyo oficial de AiaTek (partner  oficial  deElastix en la República Dominicana) se trata de dar un pantallazo general de todas las prestaciones y funcionalidades posibles con Elastix en su formato Out of The box.

El libro en su totalidad está licenciado por medio de la licencia GNU FDL lo cual permite su edición y mejora continua por parte de la comunidad y está orientado a un público recién iniciado en el mundo de la VoIP, sin ser esto un impedimento  para que usuarios avanzados puedan descubrir en el tips interesantes o simples detalles de configuraciones desconocidas por muchos.

Realmente debido a la escasa cantidad de material de consulta sobre VoIP en nuestro idioma, aportes como este deben ser tomados muy seriamente por la comunidad y deben contar con apoyo de las empresas patrocinantes como lo hizo AiaTek en este caso.

Mientras tanto felicitaciones Alfio, mi opinión sobre el libro fue mas que positiva, todo material es perfectible y espero que este formato de material de estudio y consulta en formato OpenSource se propague en la comunidad  y la misma sepa devolver su granito de arena.

Vínculo gratuito para su descarga:  Elastix a Ritmo Merengue

Tutorial de 3CX IP PBX: Qué es, para qué sirve y cómo funciona

En sinologic postearon este interesante articulo sobre 3CX la PBX bajo windows, personalmente hago instalaciones de esta PBX, considero que este anuncio vale la pena, aquí se los dejo:

Hace unos días, nos enviaron un ejemplar del nuevo libro: “3CX IP PBX Tutorial” de la editorial PacktPub, un libro que sirve perfectamente como guía y manual de referencia para todos aquellos que quieran trabajar con esta aplicación y ya hayan descargado su versión gratuita con el fín de probarlo y ver si cumple con sus espectativas.

El libro cumple perfectamente su cometido, explica prácticamente todo lo necesario para crear un sistema PBX de una manera fácil, rápida y explica los conocimientos básicos necesarios para que podamos configurar nuestras extensiones, y programar un dialplan que nos permita hacer y recibir llamadas así como configurar cuentas con proveedores IP y las tarjetas compatibles, así como configurar la integración con otras aplicaciones, extensiones remotas y diversos servicios asociados a las cuentas SIP que hayamos creado: voicemail, música en espera, menús, salas de conferencias, etc.

Sería injusto comparar 3CX y Asterisk ya que 3CX es una aplicación pensada para montar una centralita mientras que Asterisk es una aplicación pensada para hacer de herramienta de gestión de comunicaciones que igual puede hacer de centralita, de gateway y prácticamente cualquier otra función que necesitemos, por lo que aquellos que quieran montar su propia centralita, que no les importe comprar licencias, que no sepan nada de Linux pero dominen más los sistemas Windows, 3CX es una aplicación que seguro les interesará conocer.

Eso sí, como todo sistema de este tipo, cualquier característica que no traiga de serie, será mejor olvidarla.

El libro “3CX IP PBX Tutorial” introduce al lector en una filosofía basada en lo “rápido, fácil y económico” y está especialmente dirigido a aquellos usuarios que utilizan sistemas Trixbox, Elastix y otros interfaces enlatados, dando por sentado que aquellos que utilizan estos sistemas buscan montar un sistema de comunicaciones rápida, fácil y lo más barato posible pero con todas las características que puede requerir cualquier empresa para su sistema de comunicaciones. Por ello, comienza con una comparativa sobre Linux+Asterisk vs. Windows+3CX, que deja claro para quién está pensada esta aplicación: para los que no quieren complicarse con Linux y Asterisk.

3CX cuenta con una versión gratuitaotra comercial. La versión gratuita está limitada lo suficiente para que una empresa que quiera utilizarla pueda ver qué puede, y la versión comercial (cito una frase del libro: “Asterisk Free version has features comparable to 3CX Commercial edition“, algo que cualquiera que conozca Asterisk mínimamente debe imaginarse que no es cierto.)


En el libro empieza con una lista de requisitos prácticos que debe tener un servidor que vaya a ser utilizado para ejecutar esta aplicación. Al contrario de lo que uno puede pensar cuando conoce un poco Asterisk, la aplicación 3CX utiliza bastantes recursos y aunque puede ser instalado en una máquina virtual como Xen, VMWare, Parallels, VirtualBox, o cualquier otra, siempre se recomienda un sistema dedicado ya que hará bastante uso del procesador y de la memoria, además del que ya utiliza un sistema basado en Windows.

Una vez explicado los requisitos y porqué son necesarios, empieza una explicación paso a paso ilustrado con capturas de cada una de las pantallas qué hay que hacer para instalar y configurar el sistema:

Introducción
- Descarga e Instalación de 3CX
- Lista de terminales IP compatibles y cómo configurarlos para conectarlos a 3CX.
- Creación de grupos de teléfonos (para diferentes departamentos).
- Configuración y gestión de grupos de llamadas, voicemail, colas y menús interactivos.
- Gestión de cuentas de proveedores SIP para llamadas tanto entrantes como salientes.
- Configuración de la música en espera, creación de locuciones para menús y una introducción al dialplan.

Avanzando
- Avanzando con dialplan más complejos.
- Configurando extensiones remotas en internet o a través del sistema de VPN propio de 3CX.
- Grabación de llamadas.
- Faxes mediante T.30 y T.38.
- Configuración y selección del códec más idoneo en cada momento.
- Configuración de routers para evitar problemas de conexión.

Funciones especiales para Empresas
- Integración con aplicaciones de terceros: (Outlook 2007, Click-to-dial, y algunos otros)
- Cómo conectar 3CX con otras centralitas ya existentes.
- Integraciones con otros tipos de centralitas.

Hardware compatible
- Lista del hardware que 3CX soporta de forma especial, así como otro hardware que soporta gracias al uso de estándares abiertos.
- Gateways compatibles (analógicos, rdsi básicos, rdsi primarios, gsm,…)
- Dispositivos ATAs (gateways analógicos-SIP)

Labores de Mantenimiento necesario
- Realizar copias de seguridad de la configuración.
- Restaurar todo tras un desastre.
- Configurar un firewall para aumentar la seguridad.
- Monitorizando el sistema.

Integraciones especiales
- Integración especial para su propio módulo para Hoteles.
- Integración con Skype (mediante un gateway especial de 3CX compatible con Skype).
- Integración con mensajería instantánea mediante Openfire.

En resumen, “3CX IP PBX Tutorial” es un libro que bien podría tratarse del manual de usuario oficial de 3CX y que más de uno sin duda comprará para tenerlo siempre a mano y de hecho, imprescindible para aquellos que empiecen a utilizar esta aplicación.

La pega, pues que como la mayoría de los libros técnicos de esta y muchas otras editoriales, tanto la aplicación 3CX como el libro, únicamente se encuentran en inglés, por lo que seguramente este hándicap será más que suficiente para aquellos que estaban interesados en este producto y seguirán utilizando otras aplicaciones, distribuciones y tutoriales escritas en español.

Si quereis echar un vistazo, siempre podeis descargar un extracto.

De las distribuciones de Linux más populares, ¿cuál es la más liviana?

Muchos usuarios novatos o incluso experimentados se han preguntado alguna vez cuál de las distribución de Linux más populares de hoy en día es la más liviana, refiriéndose a la cantidad de recursos de hardware consumidos que nos ha obligadolinuxses2 en muchas ocasiones a tener que actualizar o cambiar nuestra máquina por una más nueva y potente.

Es por esto que los chicos de The Linux Experiment han realizado un interesante pero improvisado estudio sobre cómo se comportan las distribuciones más populares en diferentes instantes del proceso de instalación. Para este estudio se utilizaron máquinas virtuales en VirtualBox 3.1.4 (Windows) con 512 MB de RAM, 8 GB de disco duro y un procesador de tipo x86.

Los resultados fueron los siguientes:

Memoria RAM utilizada en el primer inicio



Luego de haber instalado el sistema se analizó la cantidad de memoria utilizada para iniciar el sistema por primera vez. En el gráfico anterior podemos apreciar que Kubuntu 9.10 y Mandriva 2010.0 con KDE son las que utilizan la mayor cantidad de memoria con casi 200 MB de RAM, mientras que Debian 5.0 es la que utiliza menos, sólo 75 MB de RAM.

Memoria RAM utilizada luego de instalar las actualizaciones



Esta prueba mide la cantidad de memoria utilizada al iniciar el sistema luego de haberlo actualizado. Podemos apreciar que Kubuntu sigue siendo el que consume aún más memoria al momento de iniciar con más de 300 MB de RAM consumidos, mientras que Debian sigue consumiendo los 75 MB de RAM. La gran mayoría de las otras distribuciones mantuvo o disminuyó el consumo de RAM.

Tamaño de las particiones creadas por defecto



El gráfico anterior muestra el tamaño de las diferentes particiones creadas por defecto al momento de la instalación de cada una de las distribuciones. A excepción de Debian que utiliza el sistema de archivos ext3, todas las demás distribuciones utilizan ext4.

Espacio utilizado luego de la instalación y actualización



El gráfico anterior muestra el tamaño utilizado por cada una de las distribuciones luego de haber sido instaladas y actualizadas. La distribución que utiliza más espacio es OpenSUSE 11.2 con KDE con 3.7 GB y la que utiliza el menor espacio es Debian 5.0 con menos de 1.5 GB.

Conclusiones


Las conclusiones son muy claras, la distribución que consume menos RAM y espacio en el disco duro es Debian 5.0 seguida por Xubuntu y Ubuntu 9.10. Esta información es bastante útil si aún no te has decidido por que distribución instalarle a tu cacharrito, pero es sólo una referencia mínima por lo que se recomienda probar muchas distribuciones para saber cuál realmente es la que satisface tus necesidades.

Muchos podrán criticar que este experimento está bastante incompleto ya que no se analizaron tópicos como el consumo de CPU, algunas distribuciones como Arch Linux, Gentoo, Slackware o alguna distribución minimalista especialmente diseñada para equipos con pocos recursos, pero el autor señala que la intención de estas pruebas es analizar el comportamiento de las distribuciones más populares de la actualidad, con sus instalaciones por defecto y corriendo con poca memoria RAM, cuya tarea no es menor ya que no cualquiera estaría dispuesto a darse este trabajo.

Se invita a los lectores a completar el análisis realizando nuevas pruebas y comentando sus resultados, yo personalmente les recomiendo que utilicen una herramienta llamada Phoronix Test Suite para medir el rendimiento de tu sistema.

FUENTE

Skype buscaría estandarizar su codec SILK y publicaría su código

En la pagina de www.fayerwayer.com publicaron una muy buena noticia,

Skype ha enviado el código fuente de su codec de audio SILK a Internet Engineering Task Force (IETF), la organización que define y desarrolla los estándares de Internet. Lo que busca Skype es por una parte entregar al resto del mundo un codec de alta calidad para la transmisión de voz por Internet y por otra parte, obtener mejoras a través de la revisión de este código por otros expertos.

SILK es un codec o codificador/decodificador especialmente dedicado a la transmisión de voz en tiempo real que se ha incluido en las últimas versiones de Skype para sistemas de escritorio (Windows/Mac/Linux), y pronto se llevará a los equipos móviles.  SILK cuenta con mecanismos de optimización adaptativa, esto quiere decir que a medida que trabaja se da cuenta de qué optimizaciones son necesarias y puede proveer una calidad de sonido cercana a una conversación directa con poco ancho de banda, enfocándose en la voz para no desperdiciar recursos en ruido ambiental.

Según el CTO de Skype, SILK es el resultado de tres años de desarrollo, en donde se han enfocado en crear un codec de alta calidad y escalable en varios sentidos a través de su optimización adaptativa, por ejemplo respondiendo bien a las condiciones variables de la red (lentitud/latencia) y usando adecuadamente los recursos para funcionar bien incluso en aparatos con poca potencia de procesamiento como son los equipos móviles.

En el documento enviado a IETF se encuentra el código fuente de una implementación de referencia de SILK.  Si bien el código es abierto, no se trata de Software Libre, y es aquí en donde se nota la diferencia entre los conceptos de Software Libre y Código Abierto, ya que sólo se permite usar el código para pruebas e investigación, si se quiere usar para desarrollar productos comerciales se requiere una licencia de Skype.

Links:
SILK speech codec (IETF Draft)
Advances in audio (Daniel Berg, CTO de Skype)

viernes, 12 de marzo de 2010

Paginación en PHP

Como en mi vida diaria de Ingeniero no solo tengo que lidiar con Voz Ip, hay veces que tengo que programar algo y no me acuerdo, en este caso me paso con PHP y la paginación, buscando en nuestro buen amigo google halle un buen ejemplo (link), espero que les sea de mucha utilidad.

Este articulo explica uno de los metodos mas faciles y eficientes para paginar resultados obtenidos de una base de datos en PHP.

Como primer tenemos nuestra base de datos, en nuestro caso la nombramos "noticias" y le añadimos una tabla llamada "articulos" con la siguiente estructura...

CREATE TABLE `articulos` (
`id` INT NOT NULL AUTO_INCREMENT ,
`titulo` VARCHAR( 255 ) NOT NULL ,
`descripcion` TEXT NOT NULL ,
`contenido` TEXT NOT NULL ,
`fecha` DATE NOT NULL ,
`visible` TINYINT( 1 ) NOT NULL ,
PRIMARY KEY ( `id` )
);

Nosotros hemos cargado la tabla con los titulares de un diario, la paginación final tiene este aspecto..


Pasemos a explicar el código, primero hemos creado la función de conexión a la base de datos...

function conectar()
{
$base_de_datos = "noticias";
$db_usuario = "root";
$db_password = "";




if (!($link = mysql_connect("localhost", $db_usuario, $db_password)))
{
echo "Error conectando a la base de datos.";
exit();
}
if (!mysql_select_db($base_de_datos, $link))
{
echo "Error seleccionando la base de datos.";
exit();
}
return $link;
}


No olviden modificar las variables $base_de_datos, $db_usuario y $db_password con sus correspondientes valores, esa función puede ir en un include (seria lo mas recomendado), luego llamamos a la funcion...

$db = conectar();

Ya tenemos la variable $db apuntada a nuestra base de datos el siguiente paso es definir los valores por defecto, como por ejemplo cada cuantos artículos paginar...

$registros = 3;

Y detectar si la variable $pagina (indica el numero de pagina actual) esta definida, si no es así le damos el valor 1 ósea que si no se paso por la url la variable $pagina (por ejemplo: "paginacion.php?pagina=2") entramos a la pagina 1 directamente...



$pagina = $_GET["pagina"];



if (!$pagina) {
$inicio = 0;
$pagina = 1;
}
else {
$inicio = ($pagina - 1) * $registros;
}


Como dato adicional la variable $inicio indica desde que registro empezar a mostrar los resultados. Pasemos al corazón de la paginación, miremos primero el código...



$resultados = mysql_query("SELECT id FROM articulos WHERE visible = 1");
$total_registros = mysql_num_rows($resultados);
$resultados = mysql_query("SELECT * FROM articulos WHERE visible = 1 ORDER BY fecha DESC LIMIT $inicio, $registros");
$total_paginas = ceil($total_registros / $registros);


Como ven realizamos 2 consultas similares en cuanto a su criterio de selección ("WHERE visible = 1"). Con la primer consulta obtenemos el numero de resultados totales...



$resultados = mysql_query("SELECT id FROM articulos WHERE visible = 1");
$total_registros = mysql_num_rows($resultados);


Ese dato de $total_registros nos sirve para poder determinar la cantidad de paginas. La segunda consulta tiene en el SQL dos elementos a analizar, el primero es el ORDER BY que lo que hace es ordenar los resultados por fecha y de forma descendente ("DESC") en caso contrario usaríamos "ASC".

El segundo elemento a ver es LIMIT $inicio, $registros esa cláusula SQL cumple la función de limitar los resultados devueltos, el primer valor pasado como parámetro indica desde que registro empezar a devolver los resultados y el segundo parámetro indica la cantidad de registros que debe devolver desde $inicio.

Luego solo queda el bucle que devuelve los resultados...

while($articulo=mysql_fetch_array($resultados)) {



echo "<b>".$articulo["titulo"]."</b><br>";
echo "<font color='#666666'>".$articulo["descripcion"]."</font><br><br><br>";




}

Como parte final nos queda lo que seria el navegador de paginas...


El código del navegador de paginas se divide en tres partes, primero la que muestra el link a la pagina anterior

if(($pagina - 1) > 0) {
echo "<a href='paginacion.php?pagina=".($pagina-1)."'>< Anterior</a> ";
}




El link a la pagina anterior será visible siempre y cuando no estemos en la primer pagina ($pagina - 1) > 0). La segunda parte del navegador de paginas seria la que muestra la cantidad de paginas...

for ($i=1; $i<=$total_paginas; $i++){
if ($pagina == $i) {
echo "<b>".$pagina."</b> ";
} else {
echo "<a href='paginacion.php?pagina=$i'>$i</a> ";
} }


Y la tercer parte es la que muestra el enlace a la pagina siguiente...

if(($pagina + 1)<=$total_paginas) {
echo " <a href='paginacion.php?pagina=".($pagina+1)."'>Siguiente ></a>";
}


En este caso muestra el enlace siempre y cuando no estemos en la ultima pagina (($pagina + 1)<=$total_paginas).

Podes descargar el ejemplo, lee el archivo leee.txt que esta dentro del ZIP para poder importar la base de datos y así utilizar el ejemplo.

Un agradecimiento a la web: www.elguruprogramador.com.ar por esta pasta de codigo sencillo y muy bien explicados

NOTA: En el archivo paginación.php agregar $pagina = $_GET["pag"];