Archive for August, 2009

Passing variables between templates (Smarty)

Tuesday, August 25th, 2009

For a couple of months now I’ve been working with the WCM system from Nstein.

A client uses it to deploy its website. It looks cool and easy to use but as I just said it looks so.

It uses Smarty templates to generate webpages and content. For this particular client WCM has been ‘pimped’ and a lot of stuff happened. First of all the use of templates is totally wasted, instead of having a top and footer templates you copy and paste the code anyway that’s not why I’m writing this post, the thing is that I had a tpl which was included inside another tpl nested in another tpl. When trying to set the value of one Smarty variable in the deepest nested tpl I couldn’t get it to work! Damn! a coworker helped me and after a couple of hours he gave me the answer.

Declare the variable on the highest level tpl, then assign it and finally call it through Smarty’s get_template_vars like this:

$variable_to_use = “some value”; //Declaration

$smarty_object->assign(“variable_assigned”,$variable_to_use); //Making it available for Smarty

$variable_to_use = get_template_vars(“variable_assigned”); //Call from the deepest nesting level tpl file

It’s really easy but I wasn’t aware of it.

I got so angry till my coworker gave me this tip that I thought it should be an experience to post in my blog so here it is.

Javascript events & parameters

Monday, August 24th, 2009

Having learned the right way to register events to an object with javascript lead me to another couple of issues.
First I created a wrapper for the event handler so I might be able to manage both IE and FF, I based the wrapper on this.
The wrapper call ended like this:

addEvent(object,event,function);

The problem here was, what if the function parameter needs parameters??? I thought it was a big deal but after making a couple of Google searches I found that I could wrapp this function.

Let me put an example:

<script language=”javascript” type=”text/javascript”>
<!–
//an example function that doesn’t need parameters
function popAlert() {
alert(‘yadda yadda’);
}
addEventListener(obj,’click’,popAlert); //whenever obj gets clicked function popAlert will be executed

–>

</script>

This was no problem at all works perfect but there are some cases where the function called needs parameters. how could I do that?! I tried the following:

addEventListener(obj,’click’,popAlert(‘parameter’));

WRONG! didn’t work so I was like about to give up when I found I could do something like this:

addEventListener(obj,’click’,function(){popAlert(‘parameter’);});

This actually works so now I may pass parameters to any function I register to an event!

In the case I needed to pass an actual event the function would end up looking like this:

addEventListener(obj,’click’,function(e){doOnEvent(e);});

Note: This also applies for IE attachEvent.

Give it a try!

Javascript popups

Monday, August 24th, 2009

Ok, I know the thing is not new, everybody knows what the following line does:

window.open(url,name,properties);

But there are some cases when you really need more from these simple line. We know it opens a new window but there are a few things we must ask ourselves 2 see if we should just leave it like that.
A couple of weeks ago I was very happy coding an application. Some screens required to open a popup, this was very simple. Every now and then I would simply add the previous line of code and it was all done. Hell broke when the customer told me: “U know what? I need that if I close the main window then all child windows should close.”
Damn! I never thought the customer would want 2 do something like this! anyway there were lots of lines of code that needed to b modified.
My first approach was really simple. Change the above line of code for something like this:

var my_window = window.open(url,name,properties);

So now everytime I closed the main window I would call this function:

my_window.close();

Cool! everything is alright now…. wrong!!!! some screens had like 10 popups so coding this was boring and was taking time. So I came up with a great solution based on a cool, simple script found here.
The thing is that I created a class that would wrapp the window open and close methods. With this class I wouldn’t have to write 1 window.close for each window since one of the method closes every popup created with it.
Here it is, happy coding!!!!

<script language=”javascript” type=”text/javascript”>
<!–
function objVentanaEmergente () {
this.ventanas = new Object;
this.objetos = new Array;

this.abre = function (ventana,url,nombre,propiedades) {
if (typeof(this.ventanas) == ‘object’) {
if (typeof(this.ventanas[ventana]) == ‘undefined’) {
this.ventanas[ventana] = window.open(url,nombre,propiedades);
this.objetos.push(ventana);
if (!this.ventanas[ventana].opener) {
this.ventanas[ventana].opener = self;
}
}
else {
this.ventanas[ventana].location.href = url;
}
if (window.focus) {
this.ventanas[ventana].focus();
}
}
return false;
};

this.quitaDeArreglo = function (ventana) {

var auxiliar = 0;
var cuantos = this.objetos.length;
var arreglo_auxiliar = new Array;
if ( cuantos > 0 ) {
for ( auxiliar = 0; auxiliar <>
if (this.objetos[auxiliar] != ventana) {
arreglo_auxiliar.push(this.objetos[auxiliar]);
}
}
this.objetos = new Array;
this.objetos = arreglo_auxiliar;
}
};

this.cierra = function (ventana) {
if (typeof(this.ventanas) == ‘object’) {
if (typeof(this.ventanas[ventana]) != ‘undefined’) {
this.quitaDeArreglo(ventana);
this.ventanas[ventana].close();
}
}
return false;
};

this.cierraTodas = function () {
var auxiliar = 0;
while (this.objetos.length > 0) {
this.cierra(this.objetos[0]);
}
this.objetos = new Array;
this.ventanas = new Object;;
};
}

var ventanas = new objVentanaEmergente();

ventanas.abre(‘mi_ventana’,’http://google.com’,’_blank’,’height=200,width=150′);
ventanas.abre(‘otra_ventana’,’http://yahoo.com’,’_blank’,’height=200,width=150′);

document.getElementById(‘cierra’).onclick = function () {
ventanas.cierra(‘mi_ventana’);
};

document.getElementById(‘cierrat’).onclick = function () {
ventanas.cierraTodas();
};
–>
</script>

Excel & PHP (again…)

Monday, August 24th, 2009

Damn! It’s been a day and I just keep finding that although some of the COM functions for Excel-PHP are similar to those of ASP there are some that still are hard to get.
First of all to set the value of a cell we have 3 different ways:
Setting the Value property, setting the Formula and setting the FormulaR1C1.
The thing is that when trying to set the FormulaR1C1 with a value that uses de RC syntax the thing throws an unknown exception!!!
This is useless since I can’t figure what the hell is going on!
Also there’s little or none info about Excel COM & PHP on the web…. crap!
As soon as I find whats wrong Ill post it here….

Found something interesting.
A formular1c1 declared like “=SUM(R[-2]C:R[-1]C)” in common VB should look like “=SUM(F(-2)C:F(-1)C)”… weird but I think Im getting closer to a final solution.
Now suppose I have Excel and I have a spanish version where the formula SUM should be SUMAformular1c1 should work with SUM but doing:

$cell->FormulaR1C1 = “=SUM(F(-2)C:F(-1)C)”;

Does not work…. Like Poco I’ll keep on tryin’ 😉

Importancia de la fase de pruebas

Monday, August 24th, 2009

Bueno durante mis años mozos jijijiji siempre me intrigaba el asunto de la famosa etapa de pruebas, ¿por qué es tan importante?
Pues hoy en día después de años de experiencia sé la importancia que tiene esta etapa. Y es que no es una simple fase de pruebas, son pruebas exhaustivas. Exhaustivas quiere decir que vamos a probar todos los caminos posibles en el flujo de los datos para validar que todos los caminos son los que se planearon y que el sistema funciona tal cual queremos.
Además esta fase nos ayuda a liberar rápidamente un sistema. Permítanme les platico un ejemplo.
Estos meses he estado involucrado en un proyecto que sinceramente ya se ha vuelto un dolor de cabeza. Primero que nada no nos dieron documentación, después el ambiente de pruebas falló y nadie supo cómo arreglarlo. No ha habido ningún papel especificando el alcance del desarrollo ni nada por el estilo. El objetivo es substituir una aplicación cliente/servidor con un programa web hecho en LAMP o WAMP. Nos decidimos por WAMP dado que había que modificar algunos Excel y archivos de Crystal Reports al vuelo.
Dado la falta de documentos el desarrollo se ha ido haciendo a prueba y error. Finalmente ha quedado ‘listo’. Siguiente paso: se le solicita al cliente que ponga a su personal a probarlo exhaustivamente para validar campos, flujo de datos y en general el funcionamiento del sistema. El cliente decide brincarse esta etapa y nos informa que le parece bien que se pruebe en paralelo con el sistema que tienen actualmente.
Aquí empezaron los problemas ¿por qué? porque aunque el sistema es vital para el funcionamiento de la empresa únicamente se utiliza cerca de 5 veces al día. Esta cantidad es totalmente ridícula para validar si el sistema funciona bien! se le explica al cliente e incluso a mis jefes los riesgos de no realizar las pruebas exhaustivas pero como ocurre en la mayoría de los casos se decidió por satisfacer una necesidad estúpida del cliente.
Esto ha implicado que los distintos caminos que puede tomar la información no se prueben del todo y además el tiempo de puesta a punto del sistema se ha extendido indefinidamente. Se reportan hasta 6 detalles semanalmente que ocupan un total de horas laborales. Yo de lujo pues descanso muchísimo pero a mi empresa le cuesta dinero, tiempo y pérdida de recursos que puede aprovechar en otro proyecto.
Si se hubieran hecho las pruebas exhaustivas el sistema estaría listo desde hace un par de semanas pero esto va para largo.
En fin, me aguantaré estar sentado un rato con riesgo de hemorroides y un ocio increíble. Estudiaré más, sacaré mis apuntes y a desarrollar otras cosas sino me voy a aburrir increíblemente.

WordPress y lentitudes

Monday, August 24th, 2009

Carajo!

Bien emocionado porque ya tenía mi blog con WordPress instalado. Todo se veía súper bien, configuré el título del blog y recordé que tenía un blog en blogger. Por mi mente pasó la idea de mudar los pocos posts que tenía ahí a este sitio…. tan trivial como copiar y pegar no?

Pues NO!!!! empiezo con el primero y pues normal, el segundo fue lento, el tercero más lento aún, los siguientes fueron una pesadilla!!! qué coño pasa? algo le sucede a mi SO? me propongo arreglarlo a pesar de que son las 2:15am….

Dado que el maldito bloqueó la máquina tuve que reiniciar el servidor!!!!

Acto seguido realicé lo siguiente:

1. Ver el log de errores de apache…

tail /var/log/httpd/error_log

Vi que aparecían ciertas líneas sospechosas:

[Mon Aug 24 01:49:43 2009] [notice] Apache/2.2.3 (CentOS) configured — resuming normal operations

[root@homeserver ~]# tail /var/log/httpd/error_log

[Mon Aug 24 01:08:24 2009] [error] [client 189.141.246.93] PHP Warning:  gzinflate() [<a href=’function.gzinflate’>function.gzinflate</a>]: buffer error in /var/www/html/lamp-ios.com/blog/wp-includes/http.php on line 1787

[Mon Aug 24 01:08:24 2009] [error] [client 189.141.246.93] PHP Warning:  gzuncompress() [<a href=’function.gzuncompress’>function.gzuncompress</a>]: data error in /var/www/html/lamp-ios.com/blog/wp-includes/http.php on line 1792

[Mon Aug 24 01:08:24 2009] [error] [client 189.141.246.93] PHP Warning:  gzinflate() [<a href=’function.gzinflate’>function.gzinflate</a>]: buffer error in /var/www/html/lamp-ios.com/blog/wp-includes/http.php on line 1787

[Mon Aug 24 01:08:24 2009] [error] [client 189.141.246.93] PHP Warning:  gzuncompress() [<a href=’function.gzuncompress’>function.gzuncompress</a>]: data error in /var/www/html/lamp-ios.com/blog/wp-includes/http.php on line 1792

[Mon Aug 24 01:49:40 2009] [notice] core dump file size limit raised to 4294967295 bytes

2. Qué hay en esas líneas?

/**

* Decompression of deflated string.

*

* Will attempt to decompress using the RFC 1950 standard, and if that fails

* then the RFC 1951 standard deflate will be attempted. Finally, the RFC

* 1952 standard gzip decode will be attempted. If all fail, then the

* original compressed string will be returned.

*

* @since 2.8

*

* @param string $compressed String to decompress.

* @param int $length The optional length of the compressed data.

* @return string|bool False on failure.

*/

function decompress( $compressed, $length = null ) {

$decompressed = gzinflate( $compressed );

if ( false !== $decompressed )

return $decompressed;

$decompressed = gzuncompress( $compressed );

if ( false !== $decompressed )

return $decompressed;

if ( function_exists(‘gzdecode’) ) {

$decompressed = gzdecode( $compressed );

if ( false !== $decompressed )

return $decompressed;

}

return $compressed;

}

3. Cómo se arregla? Pues busqué en google y encontré muchas soluciones que decían que borrara la función, que le pusiera el “return $compressed;” al principio pero la verdad no me parecía lógico…. más adelante algún ser razonable (MartyThornley) mencionó lo siguiente (la fuente de la información es esta):

Just tried a quick fix and it seemed to work for now:

Changed line 1787 from

$decompressed = gzinflate( $compressed );

to:

if (false !== $compressed) $decompressed = gzinflate( $compressed );

The idea being that the error said it was a data error, so that line must not like whatever is coming through in that $compressed variable.

This might be a better solution than just deleting. That way if some other functions need to use that $compressed variable, it should still work. Right?

Lo que comenta me pareció coherente aunque la solución fue burda. La definición de la función indica que se va a recibir un string pero nunca se valida si el string está vacío y al parecer las funciones de descompresión se “atontan” si el string está vacío. Para no hacer el cuento largo la función finalmente quedó así y funciona ok.

/**

* Decompression of deflated string.

*

* Will attempt to decompress using the RFC 1950 standard, and if that fails

* then the RFC 1951 standard deflate will be attempted. Finally, the RFC

* 1952 standard gzip decode will be attempted. If all fail, then the

* original compressed string will be returned.

*

* @since 2.8

*

* @param string $compressed String to decompress.

* @param int $length The optional length of the compressed data.

* @return string|bool False on failure.

*/

function decompress( $compressed, $length = null ) {

if(!empty($compressed) and !is_null($compressed)){ //added this line to avoid error

$decompressed = gzinflate( $compressed );

if ( false !== $decompressed )

return $decompressed;

$decompressed = gzuncompress( $compressed );

if ( false !== $decompressed )

return $decompressed;

if ( function_exists(‘gzdecode’) ) {

$decompressed = gzdecode( $compressed );

if ( false !== $decompressed )

return $decompressed;

}

}

return $compressed;

}

[Mon Aug 24 01:49:43 2009] [notice] Apache/2.2.3 (CentOS) configured — resuming normal operations
[root@homeserver ~]# tail /var/log/httpd/error_log
[Mon Aug 24 01:08:24 2009] [error] [client 189.141.246.93] PHP Warning:  gzinflate() [<a href=’function.gzinflate’>function.gzinflate</a>]: buffer error in /var/www/html/lamp-ios.com/blog/wp-includes/http.php on line 1787
[Mon Aug 24 01:08:24 2009] [error] [client 189.141.246.93] PHP Warning:  gzuncompress() [<a href=’function.gzuncompress’>function.gzuncompress</a>]: data error in /var/www/html/lamp-ios.com/blog/wp-includes/http.php on line 1792
[Mon Aug 24 01:08:24 2009] [error] [client 189.141.246.93] PHP Warning:  gzinflate() [<a href=’function.gzinflate’>function.gzinflate</a>]: buffer error in /var/www/html/lamp-ios.com/blog/wp-includes/http.php on line 1787
[Mon Aug 24 01:08:24 2009] [error] [client 189.141.246.93] PHP Warning:  gzuncompress() [<a href=’function.gzuncompress’>function.gzuncompress</a>]: data error in /var/www/html/lamp-ios.com/blog/wp-includes/http.php on line 1792
[Mon Aug 24 01:49:40 2009] [notice] core dump file size limit raised to 4294967295 bytes

esgay.com

Monday, August 24th, 2009

Bueno, ya todo mundo conoce esta página muy famosa por la broma y por las dificultades por las que atravesó.
No quiero entrar en detalles pues la página explica muy detalladamente los problemas legales en los que se metió. Mi interés corre por la parte de su funcionamiento.
Para quien no lo sepa la broma funciona así: link
En mi trabajo les interesó muchísimo saber cómo se hace esto y pues obviamente me encargaron la tarea de hacer algo que funcionara igual.
Si no sabes nada de Apache y PHP este tema será muy confuso pero es muy sencillo y he podido reproducirlo.
El truco consiste en dos cosas:
1. Modificar un par de cosas del servidor web.
2. Generar un script que pinte lo que quieras.
En realidad ambos pasos son muy sencillos; para el primero basta decirle al servidor web que acepte cualquiser subdominio. Esto es que si tenemos un dominio como midominio.com nuestro servidor deberá aceptar tantos subdominios como a mí se me ocurra: juanito.midominio.com, el.subdominio.midominio.com, etc.
Cómo se hace? Mira aquí.
Para el punto 2 les dejo esta liga.
Para verla funcionando prueben poniendo su nombre separado por puntos antes de esgay.lamp-ios.com como por ejemplo (nombre ficticio, no alude a ninguna persona):jaime.godinez.martinez.esgay.lamp-ios.com
Quería continuar con el tema de ayer pero ya me dió sueño, al rato pondré más info.
Saludos

Extendiendo las propiedades de los objetos en Javascript

Monday, August 24th, 2009

Como muchos sabemos Javascript (que no es lo mismo que Java) es un lenguaje que está muy presente por la aparición de Ajax(Asynchronous Javascript & XML).
Para los proramadores web es un lenguaje muy sencillo. Realmente la complejidad aparece en los exploradores pues cada uno implementa Javascript de una forma diferente. Aquí es donde me ha dado serios problemas.
Mi idea es poder extender las funcionalidades de ciertos objetos al agregar métodos y propiedades. Navegando por internet encuentro que es posible cualquiera de las siguientes maneras.
Para una propiedad o método:
Object.prototype.propiedad1 = 10;
Object.propiedad1 = 10;
Object[“propiedad1″] = 10;
Sucede que pruebo esto en FF y funciona increiblemente bien. La gran desilusión viene cuando se intenta implementar en IE.
Sucede que en FF todos los elementos son heredados de la clase Object y al agregar un método/propiedad a esa clase pues los elementos la heredan automáticamente. Pero esto no ocurre en IE, esto aún cuando al debuguear se encuentra que, por decir un ejemplo, el elemento input type=”text” hereda de object.
¿Cómo ver esto?

<script language=”javascript” type=”text/javascript”>
<!–
alert(typeof(document.getElementById(‘[id del objeto]’));
–>
</script>

En ambos casos nos dice ‘object’.
¿Cómo implementar entonces métodos/propiedades a todos los objetos HTML en IE?
En cuanto encuentre la maldita forma publico mi respuesta.
Ahora bien agradecería si alguien tiene algo que comentar.

MyODBC

Monday, August 24th, 2009

Bueno, que continuando con el proyecto me encuentro con que el connector ODBC de MySQL en su version 3.51 hace algunas cosas extrañas.
No detallaré todas y cada una de ellas, simplemente mencionaré una de ellas.
Cualquier tabla o campo cuyo nombre supere los 21 caracteres se recorta a 21 caracteres!
Por qué razón no lo sé, pero la cuestión es que me estaba volviendo loco y ya estaba pensando en renombrar las tablas de mi BD!!!! Con cerca de 60 tablas y algunas con más de 20 campos sería una labor de flojera. Pero la solución llegó después de continuar investigando un poco:

http://bugs.mysql.com/bug.php?id=32864

Simplemente bajé el conector 5.1 y el asunto quedó solucionado.

Update: En este caso hay que actualizar el valor del registro del que hablo en el post anterior, lo único que hay que hacer es cambiar el 3 por un 5 y listo!

Crystal Reports 10 & MySQL

Monday, August 24th, 2009

Las grandes dificultades que uno se encuentra al hacer un proyecto.
Como comentaba en una entrada anterior estamos en un proyecto que necesita generar a través de CR10 unos PDF’s y XLS’s. Todo marcha a la perfección, los archivos se generan ok pero el único detalle es que ahora en vez de funcionar con MS-SQL Server funcionarán con MySQL. La muda de base es transparente, no hay problemas de ningún tipo y los script de ABC funcionan correctamente. El problema viene al conectar los reportes de CR!
Qué sucede? bueno primero CR no soporta MySQL de manera directa así que se conecta a través del ODBC de MySQL que se puede descargar de aquí:

http://dev.mysql.com/downloads/connector/

Aparentemente todo funciona ok con este odbc pero oh sorpresa, en caso de que el SQL generado por CR10 sea más complicado y utilice Outer Joins entra en escena una pesadilla!
Sucede que CR10 cuando utiliza Outer Joins genera un script con una sintáxis que el ODBC de MySQL no entiende!, son unas pocas letras en cuestión:
{oj …… }
Aquí truena el query y CR10 es incapaz de traer un registro.
Cómo solucionarlo?! me estaba generando una cantidad enorme de canas verdes, lo que debería de ser una adecuación transparente se estaba convirtiendo en mi peor pesadilla.
No encontré manera alguna de desactivar eso!
Gracias a dios en Google encontré la respuesta adecuada y los caminos por los que me llevó eran totalmente sorprendentes.
El string de búsqueda fue:
“{oj” mysql crystal reports
Tal cual con dobles comillas y todo. en fin el primer y segundo resultado de la búsqueda me llevaron a la solución. La lectura no fue del todo sencilla, decenas de colegas tenían el mismo problema y a pesar de que lo resolvieron de repente dejaban semanas sin reportar nada jajaja pero aquí mi determinación por encontrar una respuesta me llevó por el camino correcto.
Caí en esta página:
http://bugs.mysql.com/bug.php?id=18563
Como bien lo hace notar MySQL NO es un error/bug de ellos, más bien es un asunto de CR10.
El chiste es que después de leer encontré esta liga:

http://technicalsupport.businessobjects.com/KanisaSupportSite/search.do?cmd=displayKC&docType=kc&externalId=c2016114&sliceId=&dialogID=16742671&stateId=1%200%2016744519

En pocas palabras es el tema en cuestión y la respuesta que da es que hay que agregar un registro a CR para que omita esa sintáxis al usar el MyODBC.
Hay que seleccionar entre varias opciones:

Para Crystal Reports 10:
------------------------

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Crystal Decisions\10.0\
Crystal Reports\Database\QueryBuilder\OuterJoinEscSeq]
"NoOuterJoinEscSeq"="MyODBC3"

Para Crystal Reports XI Release 1:
-----------------------------------

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Business Objects\Suite 11.0\
Crystal Reports\Database\Querybuilder\OuterJoinEscSeq]
"NoOuterJoinEscSeq"="MYODBC3, libmyodbc3"

Para Crystal Reports XI Release 2:
-----------------------------------

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Business Objects\Suite 11.5\
Crystal Reports\Database\Querybuilder\OuterJoinEscSeq]
"NoOuterJoinEscSeq"="MYODBC3, libmyodbc3"

Cualquiera ingresarla en un block de notas y guardarla con la extensión .reg, darle doble click y esperar que se agregue el registro.
Ahora bien, hice lo anterior y seguía apareciendo la sintáxis!!!! bueno ya un poco más tranquilo decidí revisar si acaso el registro estaba bien agregado… sorpresa!!! no estaba bien así que lo agregué a manita.

Cerré y ejecuté de nuevo CR10 y voilá! todo ok!
Ahora sí, a continuar con mi trabajo y terminarlo rápidamente. Espero que quien lea esto solucione su problema.
Saludos & happy coding!