miércoles, abril 28, 2010

Adendum a la generación en Word con PHP


Tuve un problema al sustituir campos que contienen saltos de línea, ya que dichos saltos no aparecían en el texto reemplazado sino que todo quedaba junto haciéndolo ilegible.

Tuve que comenzar con la Wikipedia, http://en.wikipedia.org/wiki/Rich_Text_Format, para ir entendiendo un poco del formato RTF, pensé que sería necesario ir a leer bastante de la especificación para entender mejor que hacer pero no fue necesario.

Resulta que los saltos de línea (representados en php como "\r" y "\n) no se utilizan con los caracteres especiales de cualquier codificación, sino que en su lugar se utiliza el código especial \par

Así que, suponiendo que, la variable que tiene saltos de línea en su código se llama parrafo ($parrafo), basta con sustituir los caracteres de salto de línea por ese código especial:

$parrafo = str_replace("\n", ' \par ',$parrafo);

Y luego la agregamos a nuestra plantilla

$archivo = str_replace('tag_parrafo',csv_encode_conv($parrafo), $archivo);

Y listo!!!

martes, abril 27, 2010

Generando un documento Word con formato en PHP

Me costó un trabajo impresionante lograrlo, pero al final aquí está. Comencemos por algunos hechos:

  • Para generar archivos de Word en nuestro servidor web sería útil a través de una plantilla de la cual solo baste con modificar los datos.
  • Ésta plantilla debe estar en formato de texto plano para poder editarla con PHP, los documentos de Word, y en general los de Office, están hechos en archivos comprimidos que contienen a su vez múltiples archivos con el documento y metainformación, si no me crees basta con que cambies la extensión de uno de éstos archivos a .zip o .tar y lo abras con 7-zip (desconozco si con Winzip o alguna otra herramienta de compresión se pueda hacer).
  • Al concluir el trabajo, el servidor no requerirá tener instalado Word para generar o editar documentos.
  • El formato con el que trabajaremos será RTF (Rich Text Format), aunque posteriormente el usuario lo descargará como un archivo .doc de Word.
  • Es un trabajo que nos tomará algún tiempo.
Lo primero que hay que hacer es crear la plantilla en Word, un formulario que se adapte a tus necesidades, en él tienes que crear algunos textos que funcionarán a manera de etiquetas que posteriormente reemplazarán su contenido por el que tu elijas (idealmente de una base de datos). Por ejemplo, vamos a suponer que tienes en tu plantilla de Word un espacio donde tienes que escribir el nombre de alguien, teniendo:

Nombre:

Delante de ese texto no tienes escrito nada, ahí es donde tendrás que agregar un texto que utilizaremos como etiqueta, asegúrate tanto como puedas que éstas etiquetas no formen parte del texto que posteriormente agregarás, por ejemplo:

Nombre: tag_Nombre

En éste caso, en algún punto nuestro programa sustituirá tag_Nombre por algún valor que nosotros decidamos. Lo mismo haremos para cada valor que vayamos a reemplazar por contenido dinámico en algún punto. Al terminar la plantilla guarda el documento con extensión .rtf.

Aquí empieza el desmadre, ahora habrá que abrir el documento generado en RTF desde algún editor de texto que lo abra como texto plano, encontrarás que parece nada legible, te pongo un ejemplo a continuación:

\par \hich\af39\dbch\af31505\loch\f39 Nombre:
\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \f39\insrsid8026758 \hich\af39\dbch\af31505\loch\f39 tag_Nombre}{\rtlch\fcs1 \af0 \ltrch\fcs0 \f39\insrsid863771

Se ve de la fruta, busca tus etiquetas, en el ejemplo resalté la que uso en negrita, fíjate que ese tag esté completo, ya que verás que algunas están dividas (por ejemplo podrías estar por una parte "tag_Nom" y por otro lado más adelante "bre", si caes en ese caso tendrás que agregar manualmente en tu editor de texto plano la parte que falta para completarlo, ojo no vayas a borrar en ese mismo editor la otra parte, guarda tu documento, vuelve a editarlo en word y ahora si borra desde ahí la parte que sobra, en el ejemplo que te comento teóricamente en word quedaría en pantalla tag_Nombrebre teniendo que borrar el último "bre"; lo mismo tendrás que hacer para cada etiqueta que hayas implementado. Cuando hayas terminado con todas las etiquetas, entonces si tendrás una plantilla lista para trabajar con PHP.

Ahora viene la chamba de PHP, comienza copiando la siguiente función, cabe señalar que yo no la escribí y la encontré en otro blog, lamentablemente no recuerdo dónde fue y me apena mucho no poder reconocerlo como se debería:

function csv_encode_conv($var, $enc='Windows-1252') {
$var = htmlentities($var, ENT_QUOTES, 'utf-8');
$var = html_entity_decode($var, ENT_QUOTES , $enc);
return $var;
}

Ésta función la utilicé para convertir mi texto de UTF-8 que es en el que está mi base de datos al formato ANSI de Windows, si tu BD está en otro código de caracteres tendrás que modificar la función, a menos que de antemano ya la tengas compatible con el ANSI de Windows. Ésta función tenla a la mano porque más adelante la utilizaremos.

Ahora habrá que invocar la plantilla en una variable php:

$archivo = file_get_contents('plantilla.rtf');

Y aquí viene la magia, supón que tienes el nombre que deseas imprimir en tu plantilla en una variable llamada nombre que proviene de la BD, insisto en que en mi ejemplo la BD está codificada en UTF-8, así que lo sustituiremos en la plantilla con la línea:

$archivo = str_replace('tag_Nombre',csv_encode_conv($nombre),$archivo);

Esa sencilla línea hace la chamba de llenar ese campo en la plantilla, así que podrás hacer lo mismo con el resto de tus etiquetas y sus respectivas variables, si tu BD está ya en formato compatible con Windows en cuanto al código de caracteres hubiera bastado:

$archivo = str_replace('tag_Nombre',$nombre,$archivo);

Una vez que has reemplazado el contenido de todas tus etiquetas, solo resta guardar tu archivo, para ello puedes hacerlo con la siguiente línea:

file_put_contents('mi_archivo.doc',$archivo);

LISTO!!!

Espero haya sido de utilidad =)

jueves, abril 22, 2010

Login lento en MySQL

Instalamos un servidor de BD en Windows, el cliente (nuestro ambiente web) corre en un Linux, la aplicación jalaba muy lenta, al hacer varias pruebas nos percatamos que el problema era el tiempo que tomaba (unos 6 segundos aprox.) el Linux en validar credenciales de MySQL, después de ello las consultas corrían bastante bien.

Si conectábamos un cliente Windows (en mi equipo para probar) al mismo servidor el tiempo de login era inmediato, así que suponíamos que el problema era con el servidor Linux.

Tras buscar soluciones, encontré un dato muy interesante, contra todas mis teorías la modificación para corregir ésta situación no se tenía que hacer en Linux, sino en el servidor de BD, basta con modificar el archivo my.ini y agregar en la sección mysqld la siguiente línea:

skip-name-resolve

Reinicié el servicio y todo jaló a la perfección, éste parámetro tiene que ver con la resolución por medio del DNS, al principio no le encontré lógica alguna, ya que la conexión que realizo la hago mediante IP y no por nombre de host, por tal motivo parecería que el DNS sirve para nada en éste caso, pero por algún motivo ésto funcionó.

Espero sea de utilidad para algunos.