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 =)

7 comentarios:

Anónimo dijo...

hola! muchas gracias, está buenísimo tu artículo, una pregunta... cómo puedo hacer para imprimir un arreglo y añadir filas a una tabla que tengo en mi plantilla en word?

Eduardo Ramos dijo...

Una solución que te puede resultar interesante es PHPDocX que además de trabajar directamente con plantillas de Word tiene muchas otras funcionalidades que permiten añadir gráficas, imágenes, texto, tablas, etcétera

Unknown dijo...

Hola Buenisimo Gracias, oye hay alguna forma q en vez de que lo guarde directamente en la carpeta, me de la opción de q me pida donde guardarlo??

Fido dijo...

Si te refieres a la ruta donde guardarlo en el servidor, entonces tendrias que agregar algun formulario. Si te refieres a donde guardarlo en el cliente, entonces podrias poner un hipervinculo en tu respuesta y pedirle al usuario que de click derecho y elija la opcion de "Guardar como...", es lo unico que se me ocurre dado que el servidor no tiene accesso al cliente.

Unknown dijo...

Gracias Fido oye otra pregunta cuando el archivo lo convierto en .rtf se vuelve muy pesado entonces cuando se genera el nuevo también pesa mucho, hay alguna forma de evitar esto??

Unknown dijo...
Este comentario ha sido eliminado por el autor.
Fido dijo...

El problema de los archivos RTF es que no tienen optimizacion de contenido, es decir, no hay compresion de ningun tipo. Un archivo legitimo de Word es, en pocas palabras, un archivo comprimido (no se si todavia se pueda, pero al menos antes les cambiabas extension a zip y podias ver todos los archivos que componian el contenido). Lamentablemente, que yo sepa, no hay forma de reducir el tamano.