Instalando manualmente MySQL


Objetivo

Esta entrada de MySQL es para completar la instalación manual que en la entrada anterior había tratado.

Al igual que la entrada anterior la instalación se realizó en una máquina con sistema operativo Windows 7 de 32 bits. Y la carpeta de trabajo es:

C:\ServerWeb\

Para este ejemplo descargué MySQL 5.5.28 versión Community Server (mysql-5.5.28-win32.zip) y esta carpeta la descomprimí en:

C:\ServerWeb\Mysql_5.5.28\

de igual manera sin espacios.

Arrancamos la consola CMD en modo administrador

y nos vamos a la siguiente ubicación o carpeta.

C:\ServerWeb\Mysql_5.5.28\

Verificamos los diferentes archivos de preconfiguración disponible en esta carpeta y copiamos el más apropiado a nuestros requerimientos, en este caso, seleccioné la versión mediana para copiarla y conservar los archivos originales:

copy my-medium.ini my.ini

Ahora procederemos a cambiar el archivo nuevo my.ini según la configuración que requiramos:

#Path to installation directory. All paths are usually resolved relative to this.
basedir="C:/ServerWeb/Mysql_5.5.28/"
#Path to the database root
datadir="C:/ServerWeb/Mysql_5.5.28/Data/"


Indicamos en la variable basedir la carpeta de instalación de MySQL y en la variable datadir la carpeta donde se almacenarán los datos de MySQL.

# The default character set that will be used when a new schema or table is
# created and no character set is defined
character-set-server=utf8


En la variable character-set-server indicamos el conjunto de caracteres usados cuando se cree un anueva base de datos o tablas predefinidamente si no se indica de manera explícita en la creación de las mismas.

# When you create a new table, you can specify which storage engine to use by
# adding an ENGINE table option to the CREATE TABLE statement
# If you omit the ENGINE option, the default storage engine is used.
default-storage-engine=INNODB
# The MySQL server can operate in different SQL modes, and can apply these modes
# differently for different clients. This capability enables each application to
# tailor the server’s operating mode to its own requirements.
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"


También se puede establecer de manera predefinida el tipo de storage engine usado cuando no se indique de manera explícita, al crear una nueva tabla con la variable default-sotrage-engine; también con la variable sql-mode se puede especificar el modo en que debe operar MySQL Server.

max_connections=50
query_cache_size=0
table_cache=256
tmp_table_size=13M
thread_cache_size=8


Algunos otros valores son establecidos para que el servidor se comporten, por ejemplo que puedan acceder múltiples conexiones y los recursos que se dispondrán para ello.

max_allowed_packet = 2M


Al modificar la variable max_allowed_packet indicamos el tamaño máximo de paquete almacenado.

#Use default-character-set as the default character set for the client and connection.
default-character-set=utf8


Por último en la variable default-character-set establecemos el conjunto de caracteres usados por los clientes y las conexiones.

Ahora vamos a registrar la ruta de ubicación de MySQL ante windows, para ello vamos a cambiar las variable de entorno llamada Path.

Se abrirá la caja de diálogo propiedades del sistema, aunque se pueden usar los pasos habituales según la versión de Windows que se tenga en uso.

Elegimos opciones avanzadas


En variables del sistema seleccionamos la variable Path.


Al final del valor de la variable Path, agregamos ; (punto y coma) y luego la ruta de ubicación de MySQL.

Ahora procederemos a instalar a MySQL como un servicio el cual he llamado MySQL5.5.28 y con la configuración que he copiado y editado según los ajustes requeridos en el archivo c:\ServerWeb\Mysql_5.5.28\my.ini.

mysqld.exe –install MySQL5.5.28 –defaults-file=c:\ServerWeb\Mysql_5.5.28\my.ini

Después de instalado el servicio se puede iniciar con la setencia en la consola de comandos de windows.

NET START MySQL5.5.28

Podemos ver que se ha podido acceder al sistema sin password alguno, inclusive para el usuario root.

SELECT host, user, password FROM mysql.user;

Verificando los usuarios ninguno tiene password.

Al salir de MySQL y cambiar el password desde la herramienta de administración de MySQL tenemos:

mysqladmin.exe -u root password "admin"

No es necesario usar la extensión .exe.

Ahora para acceder a MySQL en modo root solicitará el password de acceso, que para este ejemplo fue admin obviamente para un sistema real ha de elegirse un password más seguro.

Al verificar el estado de los password para root se puede ver que solo ha cambiado un password de los diferentes posibles…

Una manera más segura es aplicar el cambio de password a todas las posibles maneras de acceder al usuario root.

UPDATE mysql.user SET Password = PASSWORD("admin") WHERE user = 'root';
FLUSH PRIVILEGES;
SELECT host, user, password FROM mysql.user;


Al usar esta sentencia se cambian todos los passwords del usuario root.

Para evitar el acceso de manera anónima debemos eliminar el perfil.

DROP USER ”@’localhost’;

Sin embargo, esta manera podría dejar algún perfil sin borrar si se hubiese creado anteriormente.

Otra manera de eliminar el perfil de anónimo es:

DELETE FROM mysql.user WHERE user = ”;
FLUSH PRIVILEGES;

Desinstalando

Para desinstalar detenemos el servicio.

NET STOP MySQL5.5.28

Después de detenido, aplicamos la sentencia en la consola de comandos de Windows que desinstalará el servicio.

mysqld.exe –remove MySQL5.5.28

Integrando Conector Tomcat

En la entrada anterior se detalló la instalación de Tomcat manualmente.
Para poder hacer uso de MySQL con Tomcat es necesario incluir el paquete que lo permite, este paquete se llama Connector/J. Descargué el llamado mysql-connector-java-5.1.22.zip y extraje el archivo llamado mysql-connector-java-5.1.22-bin.jar pegándolo en la carpeta \lib del directorio de instalación de Tomcat, es decir en:

C:\ServerWeb\Tomcat_7.0.27\lib\

Anuncios
Publicado en MySQL, Server, Servidores Web | Etiquetado , , , , , , , | 2 comentarios

Instalando manualmente Tomcat, PHP y Httpd Lounge


Objetivo

Ya he tratado este tema anteriormente usando los instaladores basados en asistentes; ahora vamos a instalar estas mismas herramientas de manera manual.
Como el PHP para el Apache httpd no está produciendo nuevas versiones, ha surgido la alternativa de Httpd Lounge que es compatible, además de poder trabajar con Tomcat.

Las herramientas que vamos a utilizar son:

La instalación la realicé en una máquina con sistema operativo Windows 7 de 32 bits.
Al igual que la entrada anterior se va a realizar la instalación en:

C:\ServerWeb\

Httpd Lounge

Para instalar Httpd Lounge previamente debemos instalar las librerías adecuadas Microsoft Visual C++ 2010 SP1 Redistributable Package que en mi caso es x86.

Yo descargué la versión de Httpd 2.4.2 (httpd-2.4.2-win32.zip) y esta carpeta la descomprimí en:

C:\ServerWeb\Httpd_2.4.2\

como puede verse sin espacios.

Arrancamos la consola CMD en modo administrador como lo indica la siguiente imagen…

Nos vamos a la ruta

C:\ServerWeb\Httpd_2.4.2\conf\

En esta carpeta buscamos el archivo llamado httpd.conf y procedemos a editarlo según nuestros requerimientos.

Editamos el parámetro ServerRoot actualizándolo a la ruta real de instalación.

ServerRoot "c:/ServerWeb/Httpd_2.4.2"

Editamos el parámetro ServerAdmin con la dirección de correo electrónico del administrador del servidor.

ServerAdmin joseluisbz@gmail.com

Cambiamos el parámetro ServerName con el nombre del servidor y el puerto a usar.

ServerName ServerWeb:80

Editamos los parámetros DocumentRoot y Directory.

DocumentRoot "C:/ServerWeb/Httpd_2.4.2/htdocs"
<Directory "C:/ServerWeb/Httpd_2.4.2/htdocs/">

Ahora procederemos con la instalación del servidor como un servicio de Windows, para ellos nos ubicamos en la carpeta donde se encuentran los ejecutables.

C:\ServerWeb\Httpd_2.4.2\bin\

Procedemos a iniciar la instalación, modificando el nombre del servicio e indicando la ubicación del archivo del cual debe tomar la configuración.

httpd.exe -k install -n "Httpd2.4.2" -f "c:\ServerWeb\Httpd_2.4.2\conf\httpd.conf"

no es necesario incluir la extensión “.exe”
Vemos que no presentó errores, ahora vamos a iniciar el servicio.

httpd.exe -k start -n "Httpd2.4.2"

Podemos verificar que el servidor está en funcionamiento:

Desinstalando
Si por algún motivo deseamos desinstalar el servidor Httpd, procedemos a detenerlo:

httpd.exe -k stop -n "Httpd2.4.2"


y luego damos la instrucción para desinstalarlo:

httpd.exe -k uninstall -n "Httpd2.4.2"

PHP

Para que PHP trabaje con Httpd Lounge debe bajarse la versión VC9 x86 Thread Safe, debemos tener cuidado de no confundir con la versión VC9 x86 Non Thread Safe; para este proceso descargué la versión de PHP 5.4.0 (php-5.4.0-Win32-VC9-x86.zip) y esta carpeta la descomprimí en:

C:\ServerWeb\Php_5.4.0\

como puede verse sin espacios.

Accedemos a las variables del sistema ejecutando sysdm.cpl:

Al abrirse propiedades del sistema seleccionamos opciones avanzadas


Vamos a variables de entorno: En variables de entorno, en la parte inferior en la caja Variables del sistema, seleccionando la variable Path presionamos el botón Editar:
Editamos la variable path y agregamos al final la nueva ruta en donde se encuentra la carpeta de PHP: Podemos ver que la carpeta de PHP trae unos archivos de configuración preestablecidos, copiamos uno de ellos para editar y preservar los originales:

copy php.ini-production php.ini


Editamos el nuevo archivo copiado php.ini modificando el parámetro extension_dir

extension_dir = "C:\ServerWeb\Php_5.4.0\ext"

Para habilitar el rastreo de errores cambiamos el valor de la variable error_log

error_log="C:\ServerWeb\Php_5.4.0\logs\php-errors.log"

Dependiendo de como querramos usar las etiquetas de PHP debemos habilitar o no la opción short_open_tag

short_open_tag = On

Descargamos la librería adecuada para nuestra versión de PHP y Httpd php5apache2_4.dll-php-5.4-win32.zip y la extraemos en el directorio raiz de PHP.
Editamos nuevamente el archivo de configuración httpd.conf de Httpd agregando las líneas que permiten arrancarlo con PHP.

#BEGIN PHP INSTALLER EDITS – REMOVE ONLY ON UNINSTALL
PHPIniDir "C:/ServerWeb/Php_5.4.0/"
LoadModule php5_module "C:/ServerWeb/Php_5.4.0/php5apache2_4.dll"
AddType application/x-httpd-php .php
#END PHP INSTALLER EDITS – REMOVE ONLY ON UNINSTALL

Ahora reiniciamos Httpd para que se pueda usar PHP.

httpd.exe -k restart -n "Httpd2.4.2"


Para probar que PHP está funcionando correctamente creamos dentro de la carpeta htdocs de Httpd un archivo llamado index.php.

<?php phpinfo(); ?>

Se puede probar que PHP está en funcionamiento:

Tomcat

Yo descargué la versión de Tomcat 7.0.27 (apache-tomcat-7.0.27-windows-x86.zip) y esta carpeta la descomprimí en:

C:\ServerWeb\Tomcat_7.0.27\

como puede verse sin espacios.

Tal como se hizo para llegar a Variables del sistema en Variables de entorno, se realizará la adición de una nueva variable llamada JAVA_HOME presionamos el botón Nueva.

A esta variable le asignamos la dirección de la carpeta de instalación del JDK: Una vez hayamos agregado la nueva variable, presionamos el botón aceptar.

Ahora realizaremos unos pequeños cambios opcionales algunos en algunos archivos ubicados en el subdirectorio llamado bin dentro de la carpeta de Tomcat.

Con el fin de que Tomcat arranque de manera silenciosa (sin ventana de consola emergente), cambiamos en el archivo llamado setclasspath.bat la línea set _RUNJAVA

set _RUNJAVA="%JRE_HOME%\bin\javaw"

Para eliminar los espacios en el nombre del servicio (podrá generar conflictos), editamos el archivo service.bat, también editamos el nombre a mostrar del mismo.

set SERVICE_NAME=Tomcat7.0.27
set PR_DISPLAYNAME=Tomcat7.0.27


También se puede modificar la descripción relacionada con el servicio Tomcat:

set PR_DESCRIPTION=Apache Tomcat 7.0.27 Server

Para que el servicio inicie cuando Windows lo hace, modificamos la línea:

"%EXECUTABLE%" //IS//%SERVICE_NAME% --Startup auto


Una vez almacenados los cambios procedemos a realizar el proceso de instalación:

service.bat install

no es necesario incluir la extensión “.bat”
Podemos ver que el servicio efectivamente quedó instalado:
Una manera de arrancarlo por consola CMD es con:

startup.bat

De igual manera se hace necesario el permiso aprobatorio de ejecución:

Ya Tomcat está instalado, ahora vamos a realizar unos cambios que le permita Httpd entender o manejar un archivo con extensión .jsp.

Se debe descargar el connector JK, para Windows 32 se tiene que descargar tomcat-connectors-1.2.37-windows-i386-httpd-2.4.x.zip, de allí se extrae el archivo llamado mod_jk.so y se copia dentro de la carpeta modules de la carpeta de instalación de Httpd.

Dentro de la carpeta conf de la carpeta de instalación de Tomcat creamos una carpeta llamada jk y otra carpeta llamada auto.
Dentro de la carpeta jk creamos un archivo llamado workers.properties cuyo contenido será:

# BEGIN workers.properties
# Definition for Ajp13 worker
worker.list=ajp13
worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
# END workers.properties


Dentro de la carpeta auto creamos un archivo llamado mod_jk.conf con el contenido:

<IfModule !mod_jk.c>
  LoadModule jk_module "C:/ServerWeb/Httpd_2.4.2/modules/mod_jk.so"
</IfModule>
JkWorkersFile "C:/ServerWeb/Tomcat_7.0.27/conf/jk/workers.properties"
JkLogFile "C:/ServerWeb/Tomcat_7.0.27/logs/mod_jk.log"
JkLogLevel emerg
<VirtualHost *:80>
  ServerName localhost
  JkMount /*.jsp ajp13
</VirtualHost>

Tomcat16_mod_jk_AllRemoteIP.conf
De esta manera algún script .jsp podrá ser ejecutado inclusive remotamente, evitándose el inconveniente de mostrar el contenido de dicho script en vez de ejecutarse, como sucede algunas veces aún en el mismo servidor donde se ha instalado Tomcat cuando se accede através de su dirección IP.

Ahora estos cambios se los notificamos a Httpd agregando una línea al final del archivo httpd.conf:

Include "C:/ServerWeb/Tomcat_7.0.27/conf/auto/mod_jk.conf"

Ahora vamos a cambiar predefinida de Tomcat para la publicación .jsp para que sea la misma de Httpd:

<Host name="localhost" appBase="C:/ServerWeb/Httpd_2.4.2"
      unpackWARs="true" autoDeploy="true"
      xmlValidation="false" xmlNamespaceAware="false">
<Context path="" docBase="C:/ServerWeb/Httpd_2.4.2/htdocs"
      reloadable="true" />

Ahora reiniciamos Httpd para que se pueda usar con Tomcat.

httpd.exe -k restart -n "Httpd2.4.2"


y ahora lo arrancamos nuevamente

httpd.exe -k start -n "Httpd2.4.2"


Si no hubo problemas en la elección del módulo mod_jk.so no deberían mostrar mensajes de error.

Para probar que Tomcat está funcionando correctamente creamos dentro de la carpeta htdocs de Httpd un archivo llamado index.jsp.

<html>
<body>
<% out.println("Hola Mundo"); %>
</body>
</html>


Se puede probar que Tomcat está en funcionamiento:

Deteniendo
Para detener Tomcat, procedemos con la instrucción:

shutdown.bat

Desinstalando
Si lol que queremos es desinstalar Tomcat lo hacemos con la instrucción:

service.bat uninstall

Por último podemos hacer unos cambios que permita que se pueda cargar de manera prioritaria los archivos index respectivos, estos cambios se realizan en el archivo httpd.conf a la variable DirectoryIndex

DirectoryIndex index.jsp index.php index.html index.htm


Lo anterior quiere decir que primero intente cargar el archivo “index.jsp”, si no lo encuentra intentará con “index.php” y así en adelante.

Publicado en Apache, Httpd, JSP, PHP, Server, Servidores Web | Etiquetado , , , , , , , , | 3 comentarios

Subiendo Imágenes (PNG y JPG) y Archivos a MySQL con PHP y JSP y mostrarlos en RTF usando clases


Este tutorial explica usando clases como subir fotos o imágenes tipo PNG o JPG a una base de datos de MySQL, desplegarlos en un arvhivo de tipo RTF, bien sea directamente desde el sistema de archivos del Sistema Operativo o desde una base de datos de MySQL. Además establece dinámicamente la disposición de archivos para lectura de las imágenes que se van a subir y la escritura de archivos RTF generados.
Como hemos venido trabajando con PHP y JSP esta entrada no será la excepción.

Primero que todo comentaré unos cambios con respecto a la publicación anterior de este mismo tema.
Incluí un archivo llamado Personal.html, mejoré la presentación del formulario usando css en un archivo llamado Personal.css.

Código CSS (Personal.css)
Este archivo de tipo Cascading Style Sheets detalla los elementos que se utilizan en los scripts JSP y PHP en lo referente al código HTML y también en el archivo llamado Personal.html.
No se explicará el código css pues no es la intención de esta publicación.

Table {
  border-width:2px;
  border-color:rgb(200,0,0);
  border-style:groove;
  padding:3px;
  margin:3px;
  width:690px;
}

FieldSet {
  border-color:rgb(0,0,0);
  border-style:ridge;
  border-width:2px;
  padding:3px;
  width:630px;
}

Th {
  height:32px;
  background-color:rgb(127,127,127);
  color:rgb(255,255,255);
  border-style:solid;
  border-width:2px;
  border-color:rgb(0,200,0);
  padding:3px;
  margin:3px;
  font-weight:bold;
}

Td {
  height:30px;
  text-align:left;
  vertical-align:bottom;
  border-width:2px;
  border-color:rgb(0,0,200);
  border-style:ridge;
  padding:3px;
  margin:3px;
}

Label {
  display: block;
  width: 180px;
  float: left;
  clear: both;
  text-shadow: rgb(196,196,196) 2px 2px;
}
Label:hover {
  text-decoration:blink;
  font-style:oblique;
  font-weight:bold;
}

Input.Texto {
  border-width:2px;
  border-color:rgb(127,127,127);
  border-style:inset;
}
Input.Texto:hover {
  background-color:rgb(240,240,240);
  border-style:outset;
}

Input.Boton {
  background-color:rgb(255,255,255);
  color:rgb(0,0,0);
  cursor:pointer;
  width:130px;
  padding:2px;
  border-width:5px;
  border-color:rgb(127,127,127);
  border-style:double;
  margin:1px;
  font-size: 8pt; 
  font-family: Courier;
}
Input.Boton:hover {
  background-color:rgb(0,0,0);
  color:rgb(255,255,255);
  font-weight:bold;
}

Input.File {
  border-width:2px;
  border-color:rgb(127,127,127);
  border-style:inset;
  cursor:pointer;
}
Input.File:hover {
  background-color:rgb(240,240,240);
  border-style:outset;
}

DIV.map {
  padding-top: 2px;
  padding-bottom: 2px;
  margin-top: 2px;
  margin-right: 0px;
  margin-bottom: 2px;
  margin-left: 2px;
  clear: both;
  text-shadow: rgb(196,196,196) 2px 2px;
}

#p1 {
  display: block; 
  white-space: nowrap; 
  text-indent: 0
}
#p1 A {
  text-decoration:underline;
}
#p1, #p1 A {
  color:rgb(32,32,255);
  font-size:16px;
  font-family: "Lucida Console", Monospace;
}

#p1 {
  text-align: left;
  margin: 2px 2px 2px 2px;
}

P.Mensaje {
  color:rgb(32,32,32);
  font-size:15px;
  font-family: "Courier New", Monospace;
  text-shadow: rgb(196,196,196) 2px 2px;
}

Código HTML (Personal.html)
Este archivo refleja en html “puro” nuestro formulario, también incluye “Cascading Style Sheets” según el archivo Personal.css anteriormente detallado. No explicaré el código html porque no es la intención de esta publicación.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title>Registros - Personal.html</title>
    <!--
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    -->
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <link rel="stylesheet" href="Personal.css" type="text/css" />
    <link rel="shortcut icon" href="BZ.ico" type="image/x-icon" />
  </head>
  <body>
    <form method="post" name="FormOperar" enctype="multipart/form-data">
      <TABLE>
        <TR>
          <TH colspan="2">Datos Registros</TH>
        <TR>
          <TD colspan="2"><label for="Nombre">Nombres y Apellidos:</label><input type="text" id ="Nombre" name="tNombre" value="" size="30" class="Texto" />
        <TR>
          <TD><label for="Salario">Valor Salario:</label><input type="text" id="Salario" name="tSalario" value="" size="11" class="Texto" />
          <TD><label for="Ingreso">Fecha Ingreso:</label><input type="text" id="Ingreso" name="tIngreso" value="" size="10" class="Texto" />
        <TR>
          <TD colspan="2"><label for="Foto">Foto Reciente:</label><input type="file" id="Foto" name="fFoto" size="60" class="File" />
        <TR>
          <TD colspan="2"><label for="Resumen">Resumen:</label><input type="file" id="Resumen" name="fResumen" size="60" class="File" />
      </TABLE>
      <TABLE>
        <TR>
          <TH>Personal.jsp</TH>
          <TD><input type="submit" name="bCargar" value="Cargar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bListar" value="Listar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bBorrar" value="Borrar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bReset" value="Inicio JSP" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
        </TR>
        <TR>
          <TH>Personal.php</TH>
          <TD><input type="submit" name="bCargar" value="Cargar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bListar" value="Listar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bBorrar" value="Borrar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bReset" value="Inicio PHP" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
      </TABLE>
    </form>
  </body>
</html>

Script JSP (Personal.jsp)
Tal como hicimos en la entrada anterior usamos las mismo código para la importación de librerías:

<%@ page import="org.apache.commons.fileupload.*" %>
<%@ page import="org.apache.commons.fileupload.servlet.*" %>
<%@ page import="org.apache.commons.fileupload.disk.*" %>
<%@ page import="java.sql.*" %>
<%@ page import="java.util.*" %>
<%@ page import="java.io.*" %>
<%@ include file="RTF.jsp" %>

Ahora vamos a describir unas funciones en JSP que nos ayudan a entender mejor nuestro código:

<%!
  javax.servlet.jsp.JspWriter Out;
  String GetNameScript(String Script){
    return Script.substring(Script.lastIndexOf("/")+1,Script.length());
  }
  String GetPathScript(String Script){
    return Script.substring(0,Script.lastIndexOf("/")+1);
  }
  String GetStringProtocol(String Protocol){
    if (Protocol.equals("HTTP/1.1")) return "http://";
    return Protocol;
  }
  String GetStringPort(int Port){
    if (Port == 80) return "";
    return ":"+String.valueOf(Port);
  }
  void PrintMsg(String Msg){
    try {
      Out.print("<P class=\"Mensaje\">"+Msg+"</P>");
    }
    catch (Exception e) {}
  }
  void PrintErr(String Err){
    try {
      Out.print("<P style=\"color:rgb(255,0,0)\">"+Err+"</P>");
    }
    catch (Exception e) {}
  }
  void PrintLnk(String Lnk){
    try {
      Out.println("<div class=\"map\">");
      Out.println("<p id=\"p1\"><a href=\""+Lnk+"\">"+Lnk+"</a>");
      Out.println("</div>");
    }
    catch (Exception e) {}
  }
%>

Out es una variable que es útil solo para el script JSP no para el script PHP, no confundir con out. Out Nos sirve para imprimir desde un método externo al script JSP en uso.
La función GetNameScript nos permite obtener solo el nombre de nuestro Script (el que se está ejecutando).
La función GetPathScript permite obtener la ruta de la ubicación de nuestro Script, sin incluir el nombre del servidor, ni el nombre del Script.
GetStringProtocol es una función que permite saber el protocolo, en este caso http, que usamos al desplegar nuestro script.
GetStringPort Nos retorna como una cadena el puerto usado, en caso de que no sea 80, no sería necesario cambiar nuestro script.
PrintMsg Imprime la cadena de texto según el formato asignado a los mensajes, según CSS.
PrintErr Imprime la cadena de texto según el formato para los mensajes de error.
PrintLnk Imprime un vínculo, con formato de presentación definido en CSS.

Script PHP (Personal.php)
De igual manera se hizo para el respectivo script en PHP, recordemos además que es solo necesario importar el archivo RTF.php.

<?php require("RTF.php"); ?>

Y las mismas funciones descritas anteriormente.

<?php
  function GetNameScript($Script){
    return substr($Script,strripos($Script,"/")+1,strlen($Script));
  }
  function GetPathScript($Script){
    return substr($Script,0,strripos($Script,"/")+1);
  }
  function GetStringProtocol($Protocol){
    if ($Protocol=="HTTP/1.1") return "http://";
    return $Protocol;
  }
  function GetStringPort($Port){
    if ($Port == 80) return "";
    return ":".$Port;
  }
  function PrintMsg($Msg){
    print("<P class=\"Mensaje\">".$Msg."</P>");
  }
  function PrintErr($Err){
    print("<P style=\"color:rgb(255,0,0)\">".$Err."</P>");
  }
  function PrintLnk($Lnk){
    print("<div class=\"map\">");
    print("<p id=\"p1\"><a href=\"".$Lnk."\">".$Lnk."</a>");
    print("</div>");
  }
?>

Con estas definiciones de funciones se harán unos pequeños cambios en lo que respecta al código HTML de la entrada anterior referente a este tema que hemos incluido en dos archivos para separar el código HTML de los respectivos scripts JSP y PHP. Para el script Personal.php el contenido referente al Tag Head HTML lo hemos incluido en un archivo llamado TagHead.php cuyo contenido es:

  <head>
    <title>Registros - <?php print(GetNameScript($_SERVER['SCRIPT_NAME'])); ?></title>
    <!--
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    -->
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <link rel="stylesheet" href="Personal.css" type="text/css" />
    <link rel="shortcut icon" href="BZ.ico" type="image/x-icon" />
  </head>

Script JSP
Para el script Personal.jsp el contenido referente al Tag Head HTML se incluyó en el script TagHead.jsp cuyo contenido es:

  <head>
    <title>Registros - <%=GetNameScript(request.getServletPath())%></title>
    <!--
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    -->
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <link rel="stylesheet" href="Personal.css" type="text/css" />
    <link rel="shortcut icon" href="BZ.ico" type="image/x-icon" />
  </head>

También el código HTML referente al formulario se incluyó en un archivo llamado TagForm.jsp, podemos ver que se puede intercambiar de script en ejecución, para lo cual se ha incluido los botones que lo permiten, el código es el siguiente:

    <form method="post" name="FormOperar" enctype="multipart/form-data">
      <TABLE>
        <TR>
          <TH colspan="2">Datos Registros</TH>
        <TR>
          <TD colspan="2"><label for="Nombre">Nombres y Apellidos:</label><input type="text" id ="Nombre" name="tNombre" value="" size="30" class="Texto" />
        <TR>
          <TD><label for="Salario">Valor Salario:</label><input type="text" id="Salario" name="tSalario" value="" size="11" class="Texto" />
          <TD><label for="Ingreso">Fecha Ingreso:</label><input type="text" id="Ingreso" name="tIngreso" value="" size="10" class="Texto" />
        <TR>
          <TD colspan="2"><label for="Foto">Foto Reciente:</label><input type="file" id="Foto" name="fFoto" size="60" class="File" />
        <TR>
          <TD colspan="2"><label for="Resumen">Resumen:</label><input type="file" id="Resumen" name="fResumen" size="60" class="File" />
      </TABLE>
      <TABLE>
        <TR>
          <TH>Personal.jsp</TH>
          <TD><input type="submit" name="bCargar" value="Cargar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bListar" value="Listar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bBorrar" value="Borrar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bReset" value="Inicio HTML" onClick="document.FormOperar.action='Personal.html'" class="Boton" />
        </TR>
        <TR>
          <TH>Personal.php</TH>
          <TD><input type="submit" name="bCargar" value="Cargar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bListar" value="Listar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bBorrar" value="Borrar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bReset" value="Inicio PHP" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
      </TABLE>
    </form>

Script PHP
El código HTML referente al formulario se incluyó en un archivo llamado TagForm.php con código:

    <form method="post" name="FormOperar" enctype="multipart/form-data">
      <TABLE>
        <TR>
          <TH colspan="2">Datos Registros</TH>
        <TR>
          <TD colspan="2"><label for="Nombre">Nombres y Apellidos:</label><input type="text" id ="Nombre" name="tNombre" value="" size="30" class="Texto" />
        <TR>
          <TD><label for="Salario">Valor Salario:</label><input type="text" id="Salario" name="tSalario" value="" size="11" class="Texto" />
          <TD><label for="Ingreso">Fecha Ingreso:</label><input type="text" id="Ingreso" name="tIngreso" value="" size="10" class="Texto" />
        <TR>
          <TD colspan="2"><label for="Foto">Foto Reciente:</label><input type="file" id="Foto" name="fFoto" size="60" class="File" />
        <TR>
          <TD colspan="2"><label for="Resumen">Resumen:</label><input type="file" id="Resumen" name="fResumen" size="60" class="File" />
      </TABLE>
      <TABLE>
        <TR>
          <TH>Personal.jsp</TH>
          <TD><input type="submit" name="bCargar" value="Cargar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bListar" value="Listar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bBorrar" value="Borrar Datos" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
          <TD><input type="submit" name="bReset" value="Inicio JSP" onClick="document.FormOperar.action='Personal.jsp'" class="Boton" />
        </TR>
        <TR>
          <TH>Personal.php</TH>
          <TD><input type="submit" name="bCargar" value="Cargar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bListar" value="Listar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bBorrar" value="Borrar Datos" onClick="document.FormOperar.action='Personal.php'" class="Boton" />
          <TD><input type="submit" name="bReset" value="Inicio HTML" onClick="document.FormOperar.action='Personal.html'" class="Boton" />
      </TABLE>
    </form>

Los archivos TagHead.php y TagForm.jsp se incluyeron en un solo archivo llamado HTMLHead.php quedando así:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html>
  <?php include("TagHead.php"); ?>
  <body>
    <?php include("TagForm.php"); ?>

Este archivo se usa en conjunto con el archivo HTMLFoot.php cuyo contenido es:

  </body>
</html>

Script JSP
De igual manera se creó un archivo llamado HTMLHead.jsp que incluye los archivos TagHead.jsp y TagForm.jsp y su código es:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html>
  <%@ include file="TagHead.jsp" %>
  <body>
    <%@ include file="TagForm.jsp" %>

Similarmente como sucede con el código php este archivo se usa en conjunto con HTMLFoot.jsp y su código es:

  </body>
</html>

Script JSP (Personal.jsp)
Como podemos ver el código HTML se ha reducido a una línea en comparación a la manera anterior.
Ahora explicaré las variables encargadas de determinar la ruta de lectura de archivos y escritura de los mismos, adicionalmente construir su url para que se puedan descargar.

<%@ include file="HTMLHead.jsp" %>
    <%
      Out = out;

      String WebPath = GetPathScript(request.getServletPath());
      String WebRoot = GetStringProtocol(request.getProtocol())+request.getServerName()+GetStringPort(request.getServerPort())+WebPath;
      String FS = System.getProperty("file.separator");//Separador de Archivo o de Directorio
      //Buscar ruta del Script
      String ScriptRoot = application.getRealPath("")+WebPath;
      ScriptRoot = ScriptRoot.replace("\\",FS);//Reemplaza \ por FS
      ScriptRoot = ScriptRoot.replace("/",FS);//Reemplaza / por FS

Out Inicializamos la variable para poder usar el método de impresión (válido solo para JSP).
WebPath Almacena la ruta del script, sin incluir el nombre mismo del Script.
WebRoot Variable que crea una URL base teniendo en cuenta protocolo, nombre del servidor, puerto y la ruta donde se almacena el Script.
FS Almacena el separador de Archivo o de Directorio.
ScriptRoot Almacena la ruta de nuestro Script según el sistema de archivo del sistema operativo, éste se actualiza según la variable FS, para garantizar que nuestro script sea compatible con nuestro sistema operativo (Linux o Windows).

Script PHP (Personal.php)

<?php include("HTMLHead.php"); ?>
    <?php

      $WebPath = GetPathScript($_SERVER['SCRIPT_NAME']);
      $WebRoot = GetStringProtocol($_SERVER['SERVER_PROTOCOL']).$_SERVER['SERVER_NAME'].GetStringPort($_SERVER['SERVER_PORT']).$WebPath;
      $FS = DIRECTORY_SEPARATOR;//Separador de Archivo o de Directorio
      //Buscar ruta del Script
      $ScriptRoot = getenv("DOCUMENT_ROOT").$WebPath;
      $ScriptRoot = str_replace("/",$FS,$ScriptRoot);//Reemplaza / por $FS
      $ScriptRoot = str_replace("\\",$FS,$ScriptRoot);//Reemplaza \ por $FS

La conexión a MySQL se hace de la misma manera en que se explicó en la entrada anterior. Solo que para imprimir mensajes de resultado, mensajes de error se usan los métodos respectivos anteriormente explicados.

      //Conexión MySQL
      $host = "localhost";
      $User = "elusuario";
      $Pass = "laclave";
      $DB = "Empresa";
      $Enlace = new mysqli($host,$User,$Pass,$DB);
      if ($Enlace->connect_error) {
        PrintErr(sprintf("Connect Error: (%d) %s",$Enlace->connect_errno,$Enlace->connect_error));
        exit();
      }

      //Inserción
      if (isset($_POST['bCargar'])){
        $Enunciado = $Enlace->prepare("INSERT INTO Registros (Nombre,Salario,Ingreso,Foto,Resumen) VALUES(?,?,?,?,?)");
        $sNombre = utf8_encode ($_POST['tNombre']);
        $sSalario = $_POST['tSalario'];
        $sIngreso = $_POST['tIngreso'];
        $BytesFoto = NULL;
        $BytesResumen = NULL;

        $Enunciado->bind_param('sisbb',$sNombre,$sSalario,$sIngreso,$BytesFoto,$BytesResumen);
        if (is_uploaded_file($_FILES['fFoto']['tmp_name'])){
          $fiFoto = fopen($_FILES['fFoto']['tmp_name'], "rb");
          if ($fiFoto!=false){
            while (!feof($fiFoto)){
              $Enunciado->send_long_data(3, fread($fiFoto, 8192));
            }
            fclose($fiFoto);
          }
        } else {
          PrintErr(sprintf("Error Upload File: (%d) %s",$HTTP_POST_FILES['fFoto']['error'],$Enlace->error));
          exit();
        }

        if (is_uploaded_file($_FILES['fResumen']['tmp_name'])){
          $fiResumen = fopen($_FILES['fResumen']['tmp_name'], "rb");
          if ($fiResumen!=false){
            while (!feof($fiResumen)){
              $Enunciado->send_long_data(4, utf8_encode (fread($fiResumen, 8192)));
            }
            fclose($fiResumen);
          }
        } else {
          PrintErr(sprintf("Error Upload File: (%d) %s",$HTTP_POST_FILES['fResumen']['error'],$Enlace->error));
          exit();
        }

        if ($Enunciado->execute()) {
          PrintMsg("Inserción Exitosa!<br/>");
        }else {
          PrintErr(sprintf("Error: (%d) %s",$Enlace->errno,$Enlace->error));
          exit();
        }
        $Enunciado->close();
        $Enlace->close();
      }

Script JSP (Personal.jsp)
De igual manera no hay cambios para el código JSP, solo los ya indicados en cuanto a los mensajes.

      if(ServletFileUpload.isMultipartContent(request)) {
        //Cargar Parámetros del Script
        ServletFileUpload SFileUpload = new ServletFileUpload(new DiskFileItemFactory());
        Iterator iter = null;
        Hashtable Parameters = new Hashtable();
        try{
          iter = SFileUpload.parseRequest(request).iterator();
          FileItem FItem = null;
          while(iter.hasNext()){
            FItem = (FileItem)iter.next();
            if (FItem.isFormField() ){
              Parameters.put(FItem.getFieldName(), FItem.getString());
            } else {
              if (FItem.getFieldName().equals("fFoto")){
                Parameters.put(FItem.getFieldName(), FItem.getInputStream());
              }
              if (FItem.getFieldName().equals("fResumen")){
                Parameters.put(FItem.getFieldName(), FItem.getString("ISO-8859-1"));
              }
            }
          }
        }
        catch(FileUploadException e){ PrintErr(e.toString()); }

        //Conexión MySQL
        String host = "localhost";
        String User = "elusuario";
        String Pass = "laclave";
        String DB = "Empresa";
        try { Class.forName("com.mysql.jdbc.Driver"); }
        catch (ClassNotFoundException e) { PrintErr(e.toString()); }
        Connection Conexion = null;
        Statement Enunciado = null;
        ResultSet Resultado = null;
        PreparedStatement PE = null;
        try{ Conexion = DriverManager.getConnection("jdbc:mysql://"+host+"/"+DB,User,Pass); }
        catch (SQLException e) { PrintErr(e.toString()); }

        //Inserción
        if((String)Parameters.get("bCargar")!=null){
          try{
            PE = Conexion.prepareStatement("INSERT INTO Registros (Nombre,Salario,Ingreso,Foto,Resumen) VALUES(?,?,?,?,?)");
            String sNombre = (String)Parameters.get("tNombre");
            String sSalario = (String)Parameters.get("tSalario");
            String sIngreso = (String)Parameters.get("tIngreso");
            InputStream isFoto = (InputStream)Parameters.get("fFoto");
            String sResumen = (String)Parameters.get("fResumen");
            PE.setString(1,sNombre);
            PE.setInt(2,Integer.parseInt(sSalario));
            PE.setString(3,sIngreso);
            PE.setBinaryStream(4,isFoto);
            PE.setString(5,sResumen);
            PE.executeUpdate();
            PrintMsg("Inserción Exitosa!<br/>");
          }
          catch (SQLException e) { PrintErr(e.toString()); }
          catch (Exception e) { PrintErr(e.toString()); }
          finally {
            PE.close();
            Conexion.close();
          }
        }

Script PHP (Personal.php)

      //Extracción
      if (isset($_POST['bListar'])){
        $FileName = "PHP.Personal.RTF";
        $FullFileName = $ScriptRoot.$FileName;
        $WebFileName = $WebRoot.$FileName;
        $ImageJPG = $ScriptRoot.$FS."joseluisbz.jpg";
        $ImagePNG = $ScriptRoot.$FS."Empresa.png";
        $fw = fopen($FullFileName, "wb");
        if($fw){
          $FileRTF = new RTFFile();
          $iFormato = NULL;
          $iAlto = NULL;
          $iAncho = NULL;
          $ImageRTFJPG = new RTFImage($ImageJPG,$iFormato,$iAlto,$iAncho);
          if (strcmp($ImageRTFJPG->GetHexImage(),"Error")==0){
            PrintErr("Error: el Archivo ".$ImageJPG." no es PNG o JPG");
            exit();
          }
          $InfImagenJPG = $ImageRTFJPG->GetImage($ImageRTFJPG->GetHexImage(),$iFormato,$iAlto,$iAncho,100,100,$iAlto*10,$iAncho*10,0,0,0,0);

          $ImageRTFPNG = new RTFImage($ImagePNG,$iFormato,$iAlto,$iAncho);
          if (strcmp($ImageRTFPNG->GetHexImage(),"Error")==0){
            PrintErr("Error: el Archivo ".$ImagePNG." no es PNG o JPG");
            exit();
          }
          $InfImagenPNG = $ImageRTFPNG->GetImage($ImageRTFPNG->GetHexImage(),$iFormato,$iAlto,$iAncho,100,100,$iAlto*10,$iAncho*10,0,0,0,0);
          $ImageRTFIMG = NULL;
          $InfImagenIMG = NULL;
          if ($Enunciado = $Enlace->prepare("SELECT * FROM Registros")) {
            $Enunciado->execute();
            $Enunciado->bind_result($sNombre,$sSalario,$sIngreso,$BytesFoto,$BytesResumen);
            $Enunciado->store_result();
            $NumRegistros = $Enunciado->num_rows;
            $TablaDatos = NULL;
            while ($Enunciado->fetch()) {
              $FileRTF->SetBasicFormatTextFile(1,3,2,5,20);
              $FileRTF->SetOtherFormatTextFile(0,0,1);
              $FileRTF->AddText("Empresa Limitada");
              $FileRTF->InsertParg();
              $TablaDatos = new RTFTable(4,4);//4 Columnas, 4 Filas
              $TablaDatos->SetFormatTable(10,10,1,1,10,2);
              $TablaDatos->SetFormatCellsTable(0,2,10,2);
              $TablaDatos->SetWideColsTable(2000);//Columnas ancho 2000
              $TablaDatos->SetWideColTable(1,3000);//Columna 1 ancho 3000
              $TablaDatos->SetBasicFormatTextTable(1,0,0,0,12);//Formato de Texto Tabla
              $TablaDatos->SetBasicFormatTextCell(0,0,1,0,0,0,12);//Formato Texto Celda 0,0
              $TablaDatos->SetTextCell(0,1,$InfImagenPNG);
              $TablaDatos->SetTextCell(3,1,$InfImagenJPG);
              $TablaDatos->SetMergeHorzCell(1,0,1);//Mezclar Celda 1,0 Inicio = 1
              $TablaDatos->SetMergeHorzCell(2,0,2);//Mezclar Celda 2,0 Continua = 2
              $TablaDatos->SetTextCell(1,0,"Celda 1,0 con Celda 2,0");
              $TablaDatos->SetMergeHorzCell(1,3,1);//Mezclar Celda 1,3 Inicio = 1
              $TablaDatos->SetMergeHorzCell(2,3,2);//Mezclar Celda 2,3 Continua = 2
              $TablaDatos->SetTextCell(1,3,"Celda 1,3 con Celda 2,3");
              $TablaDatos->SetMergeVertCell(0,1,1);//Mezclar Celda 0,1 Inicio = 1
              $TablaDatos->SetMergeVertCell(0,2,2);//Mezclar Celda 0,2 Continua = 2
              $TablaDatos->SetMergeVertCell(3,1,1);//Mezclar Celda 3,1 Inicio = 1
              $TablaDatos->SetMergeVertCell(3,2,2);//Mezclar Celda 3,2 Continua = 2
              $FileRTF->AddElement($TablaDatos->GetTable());
              $FileRTF->InsertLine();
              $FileRTF->InsertLine();
              $FileRTF->SetBasicFormatTextFile(2,4,2,4,12);
              $FileRTF->SetOtherFormatTextFile(0,0,1);
              $FileRTF->AddText("Nombre: ");
              $FileRTF->SetOtherFormatTextFile(0,1,0);
              $FileRTF->AddText(utf8_decode($sNombre));
              $FileRTF->InsertLine();
              $FileRTF->SetOtherFormatTextFile(0,0,1);
              $FileRTF->AddText("Salario: ");
              $FileRTF->SetOtherFormatTextFile(0,1,0);
              $FileRTF->AddText($sSalario);
              $FileRTF->InsertLine();
              $ImageRTFIMG = new RTFImage($BytesFoto,$iFormato,$iAlto,$iAncho);
              $InfImagenIMG = $ImageRTFIMG->GetImage($ImageRTFIMG->GetHexImage(),$iFormato,$iAlto,$iAncho,100,100,$iAlto*10,$iAncho*10,0,0,0,0);
              $FileRTF->AddElement($InfImagenIMG);
              $FileRTF->InsertParg();//Separe Image of Text
              $FileRTF->SetOtherFormatTextFile(0,0,1);
              $FileRTF->AddText("Resumen: ");
              $FileRTF->SetOtherFormatTextFile(0,1,0);
              $FileRTF->AddText(utf8_decode($BytesResumen));
              $NumRegistros--;
              if($NumRegistros>0){
                $FileRTF->InsertPage();//Nueva Página
              }
            }
            $Enunciado->close();
          }
          $FileRTF->CloseFile();
          fwrite($fw,$FileRTF->GetFile());
          fclose($fw);
          PrintLnk($WebFileName);
          PrintMsg("Generación de Archivo RTF Exitoso!<br/>");
        } else {
          PrintErr($FullFileName." (El sistema no puede encontrar la ruta especificada)");
          exit();
        }
      }

Script JSP (Personal.jsp)

        //Extracción
        if((String)Parameters.get("bListar")!=null){
          String FileName = "JSP.Personal.RTF";
          String FullFileName = ScriptRoot+FileName;
          String WebFileName = WebRoot+FileName;
          String ImageJPG = ScriptRoot+FS+"joseluisbz.jpg";
          String ImagePNG = ScriptRoot+FS+"Empresa.png";
          try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(FullFileName));
            RTFFile FileRTF = new RTFFile();
            int[] iFormato = new int[1];
            int[] iAlto = new int[1];
            int[] iAncho = new int[1];
            RTFImage ImageRTFJPG = new RTFImage(ImageJPG,iFormato,iAlto,iAncho);
            if (ImageRTFJPG.GetHexImage().equals("Error")){
              PrintErr("Error: el Archivo "+ImageJPG+" no es PNG o JPG");
              System.exit(0);
            }
            String InfImagenJPG = ImageRTFJPG.GetImage(ImageRTFJPG.GetHexImage(),iFormato[0],iAlto[0],iAncho[0],100,100,iAlto[0]*10,iAncho[0]*10,0,0,0,0);

            RTFImage ImageRTFPNG = new RTFImage(ImagePNG,iFormato,iAlto,iAncho);
            if (ImageRTFPNG.GetHexImage().equals("Error")){
              PrintErr("Error: el Archivo "+ImagePNG+" no es PNG o JPG");
              System.exit(0);
            }
            String InfImagenPNG = ImageRTFPNG.GetImage(ImageRTFPNG.GetHexImage(),iFormato[0],iAlto[0],iAncho[0],100,100,iAlto[0]*10,iAncho[0]*10,0,0,0,0);
            RTFImage ImageRTFIMG;
            String InfImagenIMG;
            PE = Conexion.prepareStatement("SELECT * FROM Registros");
            Resultado = PE.executeQuery();
            Resultado.last();
            int NumRegistros = Resultado.getRow();Resultado.beforeFirst();
            RTFTable TablaDatos;
            while(Resultado.next()){
              FileRTF.SetBasicFormatTextFile(1,3,2,5,20);
              FileRTF.SetOtherFormatTextFile(0,0,1);
              FileRTF.AddText("Empresa Limitada");
              FileRTF.InsertParg();
              TablaDatos = new RTFTable(4,4);//4 Columnas, 4 Filas
              TablaDatos.SetFormatTable(10,10,1,1,10,2);
              TablaDatos.SetFormatCellsTable(0,2,10,2);
              TablaDatos.SetWideColsTable(2000);//Columnas ancho 2000
              TablaDatos.SetWideColTable(1,3000);//Columna 1 ancho 3000
              TablaDatos.SetBasicFormatTextTable(1,0,0,0,12);//Formato de Texto Tabla
              TablaDatos.SetBasicFormatTextCell(0,0,1,0,0,0,12);//Formato Texto Celda 0,0
              TablaDatos.SetTextCell(0,1,InfImagenPNG);
              TablaDatos.SetTextCell(3,1,InfImagenJPG);
              TablaDatos.SetMergeHorzCell(1,0,1);//Mezclar Celda 1,0 Inicio = 1
              TablaDatos.SetMergeHorzCell(2,0,2);//Mezclar Celda 2,0 Continua = 2
              TablaDatos.SetTextCell(1,0,"Celda 1,0 con Celda 2,0");
              TablaDatos.SetMergeHorzCell(1,3,1);//Mezclar Celda 1,3 Inicio = 1
              TablaDatos.SetMergeHorzCell(2,3,2);//Mezclar Celda 2,3 Continua = 2
              TablaDatos.SetTextCell(1,3,"Celda 1,3 con Celda 2,3");
              TablaDatos.SetMergeVertCell(0,1,1);//Mezclar Celda 0,1 Inicio = 1
              TablaDatos.SetMergeVertCell(0,2,2);//Mezclar Celda 0,2 Continua = 2
              TablaDatos.SetMergeVertCell(3,1,1);//Mezclar Celda 3,1 Inicio = 1
              TablaDatos.SetMergeVertCell(3,2,2);//Mezclar Celda 3,2 Continua = 2
              FileRTF.AddElement(TablaDatos.GetTable());
              FileRTF.InsertLine();
              FileRTF.InsertLine();
              FileRTF.SetBasicFormatTextFile(2,4,2,4,12);
              FileRTF.SetOtherFormatTextFile(0,0,1);
              FileRTF.AddText("Nombre: ");
              FileRTF.SetOtherFormatTextFile(0,1,0);
              FileRTF.AddText(Resultado.getString(1));
              FileRTF.InsertLine();
              FileRTF.SetOtherFormatTextFile(0,0,1);
              FileRTF.AddText("Salario: ");
              FileRTF.SetOtherFormatTextFile(0,1,0);
              FileRTF.AddText(String.valueOf(Resultado.getInt(2)));
              FileRTF.InsertLine();
              ImageRTFIMG = new RTFImage(Resultado.getBytes(4),iFormato,iAlto,iAncho);
              InfImagenIMG = ImageRTFIMG.GetImage(ImageRTFIMG.GetHexImage(),iFormato[0],iAlto[0],iAncho[0],100,100,iAlto[0]*10,iAncho[0]*10,0,0,0,0);
              FileRTF.AddElement(InfImagenIMG);
              FileRTF.InsertParg();//Separe Image of Text
              FileRTF.SetOtherFormatTextFile(0,0,1);
              FileRTF.AddText("Resumen: ");
              FileRTF.SetOtherFormatTextFile(0,1,0);
              FileRTF.AddText(Resultado.getString(5));
              NumRegistros--;
              if (NumRegistros>0){
                FileRTF.InsertPage();//Nueva Página
              }
            }
            FileRTF.CloseFile();
            bw.write(FileRTF.GetFile());
            bw.close();
            PrintLnk(WebFileName);
            PrintMsg("Generación de Archivo RTF Exitoso!<br/>");
          }
          catch (Exception e) { PrintErr(e.toString()); }
        }

Script PHP (Personal.php)

      //Eliminación
      if (isset($_POST['bBorrar'])){
        $Consulta = "DELETE FROM Registros";
        $Resultado = $Enlace->query($Consulta);
        if (!$Resultado) {
          PrintErr(sprintf("Error: (%d) %s",$Enlace->errno,$Enlace->error));
          exit();
        }
        PrintMsg("Eliminación Exitosa!<br/>");
      }

Finalizamos el script PHP con:

    ?>
<?php include("HTMLFoot.php"); ?>

Script JSP (Personal.jsp)

        //Eliminación
        if((String)Parameters.get("bBorrar")!=null){
          try {
            Enunciado = Conexion.createStatement();
            Enunciado.executeUpdate("DELETE FROM Registros");
            PrintMsg("Eliminación Exitosa!<br/>");
          }
          catch (SQLException e) { PrintErr(e.toString()); }
        }

Finalizamos el script JSP el siguiente código:

      }
    %>
<%@ include file="HTMLFoot.jsp" %>

La llave de cierre coincide con la llave de apertura de la sentencia if del objeto ServletFileUpload.

Resultados
Veamos algunos resultados:
Previamente se había cargado un registro de prueba con caracteres especiales y al presionar el botón “Listar Datos” en ambos scripts se obtienen los siguientes pantallazos.


Podemos ver el pantallazo del archivo RTF generado por los dos scripts, si se compara de manera binaria el contenido del JSP.Personal.RTF y del archivo PHP.Personal.RTF son exactamente iguales.

Para ver como se muestran los errores se presióno el botón “Cargar Datos” con el formulario vacío:

Por último se presionó el botón “Borrar Datos” y se obtuvieron los siguientes pantallazos.

Para obtener los códigos y probar estos ejemplos dejo los enlaces: Personal.zip

Publicado en JSP, MySQL, PHP, Server | Etiquetado , , , , , , , , | 6 comentarios

Script de Clases RTF para JSP y PHP


En mi entrada anterior llamada Script de Funciones RTF para JSP y PHP se crearon las funciones para tratar con archivos, tablas e imágenes; pero presentaban el inconveniente de que se podían invocar funciones de manera inapropiada y el usuario tendría que tener un conocimiento más profundo del formato RTF y su sintaxis, además de conocer las funciones y argumentos con mayor detalle.

En esta entrada se explica la creación de unas clases que cumplen los mismos propósitos, métodos públicos para que el usuario pueda crear archivos, tablas y manipular imágenes para cargarlas en los archivos RTF.

Ahora entraremos en detalle sobre nuestras clases para RTF.
Los archivos RTF.jsp y RTF.php almacenarán las mismas tres clases: RTFFile, RTFTable y RTFImage; estos dos archivos son diferentes en su contenido pero igual en propósito a los descritos en la entrada “Script de Funciones RTF para JSP y PHP“.

Script JSP (RTF.jsp)
Primero la importación…

<%@ page import="java.lang.*" %>
<%@ page import="java.io.*" %>
<%@ page errorPage ="error.jsp"%>

Detallando la clase RTFFile

<!-- RTFFile -->
<%!
  public class RTFFile {
    private String HeaderFile = "{\\rtf1"//Indicador RTF
          +"\\ansi\\ansicpg1252"//1252->Western European
          +"\\deff0\\deflang9226 \n";//9226->Español Colombia

    private String[] FamilyFont = {"\n",
          " {\\f1\\fnil\\fprq1\\fcharset0 TlwgMono;}\n",
          " {\\f2\\fswiss\\fprq1\\fcharset0 Arial;}\n",
          " {\\f3\\froman\\fprq1\\fcharset0 Times New Roman;}\n",
          " {\\f4\\fmodern\\fprq1\\fcharset0 Courier New;}\n",
          " {\\f5\\fscript\\fprq1\\fcharset0 Edwardian Script ITC;}\n"}; //Familia de Fuentes
    private String FontTable = "\n{\\fonttbl\n"+FamilyFont[0]+FamilyFont[1]
          +FamilyFont[2]+FamilyFont[3]+FamilyFont[4]+FamilyFont[5]+"}\n";//Tabla de Fuentes

    private String[] Colors = {
          "\\red0\\green0\\blue0;\n", //Negro
          "\\red0\\green0\\blue255;\n", //Azul
          "\\red0\\green255\\blue255;\n", //Cian
          "\\red0\\green255\\blue0;\n", //Verde
          "\\red255\\green0\\blue255;\n", //Magenta
          "\\red255\\green0\\blue0;\n", //Red
          "\\red255\\green255\\blue0;\n", //Amarillo
          "\\red255\\green255\\blue255;\n" //Blanco
           }; //Color de Fuentes
    private String ColorTable = "\n{\\colortbl;\n"+Colors[0]+Colors[1]+Colors[2]+Colors[3]+
          Colors[4]+Colors[5]+Colors[6]+Colors[7]+"}\n";//Tabla de Colores

    private String StartFile = HeaderFile+FontTable+ColorTable;
    private String CloseFile = "}";

    private String[] aAlign = {
      "",//  Dejar Igual
      "\\qc",//  Centrar
      "\\ql",//  Izquierda
      "\\qr",//  Derecha
      "\\qj",//  Justificar
      "\\qd" //  Distribuir
    };//Tipo De Alineación Horizontal de Texto

    private String BasicFormat = "";
    private String OtherFormat = "";
    private String RTFStringFile = "";

    private String NewParg = "\\par ";//Nuevo Parágrafo
    private String NewPage = "\n\\page \\par \n";//Nueva Página
    private String NewLine = "\n\\line";//Nueva Línea

    RTFFile() {
      ResetFile();
    }

    public void ResetFile(){
      this.RTFStringFile = this.StartFile;
    }

    public void CloseFile(){
      this.RTFStringFile += this.CloseFile;
    }

    public String GetFile(){
      return this.RTFStringFile;
    }

    public void InsertLine(){
      this.RTFStringFile += this.NewLine;
    }

    public void InsertPage(){
      this.RTFStringFile += this.NewPage;
    }

    public void InsertParg(){
      this.RTFStringFile += this.NewParg;
    }

    public void AddText(String Text){
      this.RTFStringFile += this.BasicFormat;
      this.RTFStringFile += this.OtherFormat;
      this.RTFStringFile += Text;
      this.RTFStringFile += "\n";
    }

    public void AddElement(String Element){
      this.RTFStringFile += Element;
    }

    public void SetBasicFormatTextFile(int Align, int CFrnt, int CFond, int Fuente, int Talla) {
      String sCFrnt = "\\cf"+String.valueOf(CFrnt);
      String sCFond = "\\highlight"+String.valueOf(CFond);
      String sFuente = "\\f"+String.valueOf(Fuente);
      String sTalla = "\\fs"+String.valueOf(2*Talla);
      this.BasicFormat = this.aAlign[Align]+sCFrnt+sCFond+sFuente+sTalla+"\n";
    }

    public void SetOtherFormatTextFile(int Negrt, int Italc, int Sbryd) {
      String sNegrt = Negrt==0?"\\b0":"\\b";//  Negrita
      String sItalc = Italc==0?"\\i0":"\\i";//  Itálica
      String sSbryd = Sbryd==0?"\\ul0":"\\ul";// Subrayar
      this.OtherFormat = sNegrt+sItalc+sSbryd+"\n";
    }
  }
%>

La clase RTFFile permite crear un archivo de tipo RTF al que le podemos siempre agregar elementos u objetos básicos, nunca retirar, solo limpiar o redisponerlo.

HeaderFile establece codificación y lenguaje predefinido, en mi caso Colombia.
FamilyFont Es un arreglo que nos permite definir nuestro conjunto de familia de fuentes.
FontTable Establece la tabla de fuentes siguiendo el formato interno de RTF.
Colors Este arreglo permite establecer los colores que se usarán en nuestro archivo RTF.
ColorTable Establece la tabla de colores siguiendo el formato de RTF.
StartFile Crea el inicio del archivo RTF, con sus objetos característicos.
CloseFile Es una cadena para cerrar finalmente el archivo RTF cuando se cree.

aAlign Es un arreglo que permite identificar la alineación que se usará en un texto.
BasicFormat Es una cadena que almacena el formato básico en uso del archivo, siempre que se requiera desplegar o mostrar un texto se usará el formato almacenado en esta cadena.
OtherFormat Al igual que el formato básico, esta cadena almacenará formato opcional, es decir no requerido para desplegar un texto en un archivo RTF; aunque internamente siempre acompañará al texto en cuestion, solo que desactaivará los formatos no aplicados.

RTFStringFile Almacena el contenido real del archivo RTF, todo lo que se agregue al archivo RTF, será agregado a esta cadena.

NewParg Es una cadena que se utiliza para agragar un nuevo parágrafo al archivo RTF.
NewPage Es una cadena que sirve para agregar una nueva página al archivo RTF.
NewLine Es una cadena útil para insertar una nueva línea al archivo RTF.

RTFFile() Es el constructor de la clase, al invocarse redispone el archivo RTF.
ResetFile() Limpia el contenido del archivo y solo pone lo que debería llevar al inicio.
CloseFile() Agrega la cadena del cierre o indicador de finalización del archivo.
GetFile() Retorna el contenido del archivo, es decir, el contenido de la cadena RTFStringFile.

InsertLine() Es un método que agrega una nueva línea al archivo RTF.
InsertPage() Este método agrega una página al final del archivo RTF.
InsertParg() Es un método que permite agregar un nuevo parágrafo a nuestro archivo RTF.

AddText(String Text) Permite agregar un texto al final del archivo teniendo encuenta los formatos básicos establecidos en BasicFormat y los formatos opcionales establecidos en OtherFormat.

AddElement(String Element) Permite agregar un elemento al archivo sin tener en cuenta formato alguno.

SetBasicFormatTextFile(int Align, int CFrnt, int CFond, int Fuente, int Talla) Este método permite indicar el formato básico a utilizar inmediatamente de que se llame al mismo. Los parámetros a esteblecer son: Align (Alineación del texto), CFrnt (Color del texto), CFond (Color de fondo), Fuente (Tipo de fuente) y Talla (Tamaño de la fuente).
Estos parámetros se almacenarán en la cadena BasicFormat.

SetOtherFormatTextFile(int Negrt, int Italc, int Sbryd) Similarmente al anterior permite modificar el formato del texto, en caso de que algún parámetro no sea aplicado se aplicará la desactivación del mismo. Los parámetros a establecer son: Negrt (Aplicación de texto en negrita), Italc (Aplicación de texto en itálica) y Sbryd (Aplicación de texto en subrayado). De igual manera los parámetros se almacenarán en la cadena OtherFormat.

Script PHP (RTF.php)
No es necesario hacer importación.
Entonces comencemos con la clase RTFFile

<!-- RTFFile -->
<?php
  class RTFFile {
    private $StartFile = "";
    private $CloseFile = "}";

    private $aAlign = array(
      "",//  Dejar Igual
      "\\qc",//  Centrar
      "\\ql",//  Izquierda
      "\\qr",//  Derecha
      "\\qj",//  Justificar
      "\\qd" //  Distribuir
    );//Tipo De Alineación Horizontal de Texto

    private $BasicFormat = "";
    private $OtherFormat = "";
    private $RTFStringFile = "";

    private $NewParg = "\\par ";//Nuevo Parágrafo
    private $NewPage = "\n\\page \\par \n";//Nueva Página
    private $NewLine = "\n\\line";//Nueva Línea

    private function SetStartFile() {
      $HeaderFile = "{\\rtf1"//Indicador RTF
          ."\\ansi\\ansicpg1252"//1252->Western European
          ."\\deff0\\deflang9226 \n";//9226->Español Colombia

      $FamilyFont = array("\n",
          " {\\f1\\fnil\\fprq1\\fcharset0 TlwgMono;}\n",
          " {\\f2\\fswiss\\fprq1\\fcharset0 Arial;}\n",
          " {\\f3\\froman\\fprq1\\fcharset0 Times New Roman;}\n",
          " {\\f4\\fmodern\\fprq1\\fcharset0 Courier New;}\n",
          " {\\f5\\fscript\\fprq1\\fcharset0 Edwardian Script ITC;}\n"); //Familia de Fuentes
      $FontTable = "\n{\\fonttbl\n".$FamilyFont[0].$FamilyFont[1]
            .$FamilyFont[2].$FamilyFont[3].$FamilyFont[4].$FamilyFont[5]."}\n";//Tabla de Fuentes

      $Colors = array(
          "\\red0\\green0\\blue0;\n", //Negro
          "\\red0\\green0\\blue255;\n", //Azul
          "\\red0\\green255\\blue255;\n", //Cian
          "\\red0\\green255\\blue0;\n", //Verde
          "\\red255\\green0\\blue255;\n", //Magenta
          "\\red255\\green0\\blue0;\n", //Red
          "\\red255\\green255\\blue0;\n", //Amarillo
          "\\red255\\green255\\blue255;\n" //Blanco
           ); //Color de Fuentes

      $ColorTable = "\n{\\colortbl;\n".$Colors[0].$Colors[1].$Colors[2].$Colors[3].
            $Colors[4].$Colors[5].$Colors[6].$Colors[7]."}\n";//Tabla de Colores

      $this->StartFile = $HeaderFile.$FontTable.$ColorTable;  

    }

    public function __construct() {
      $this->ResetFile();
    }

    public function ResetFile(){
      $this->SetStartFile();
      $this->RTFStringFile = $this->StartFile;
    }

    public function CloseFile(){
      $this->RTFStringFile .= $this->CloseFile;
    }

    public function GetFile(){
      return $this->RTFStringFile;
    }

    public function InsertLine(){
      $this->RTFStringFile .= $this->NewLine;
    }

    public function InsertPage(){
      $this->RTFStringFile .= $this->NewPage;
    }

    public function InsertParg(){
      $this->RTFStringFile .= $this->NewParg;
    }

    public function AddText($Text){
      $this->RTFStringFile .= $this->BasicFormat;
      $this->RTFStringFile .= $this->OtherFormat;
      $this->RTFStringFile .= $Text;
      $this->RTFStringFile .= "\n";
    }

    public function AddElement($Element){
      $this->RTFStringFile .= $Element;
    }

    public function SetBasicFormatTextFile($Align, $CFrnt, $CFond, $Fuente, $Talla) {
      $sCFrnt = "\\cf".$CFrnt;
      $sCFond = "\\highlight".$CFond;
      $sFuente = "\\f".$Fuente;
      $sTalla = "\\fs".(2*$Talla);
      global $aAlign;
      $this->BasicFormat = $this->aAlign[$Align].$sCFrnt.$sCFond.$sFuente.$sTalla."\n";
    }

    public function SetOtherFormatTextFile($Negrt,$Italc,$Sbryd) {
      $sNegrt = ($Negrt==0)?"\\b0":"\\b";//  Negrita
      $sItalc = ($Italc==0)?"\\i0":"\\i";//  Itálica
      $sSbryd = ($Sbryd==0)?"\\ul0":"\\ul";// Subrayar
      $sFrmtSP = $sNegrt.$sItalc.$sSbryd."\n";
      $this->OtherFormat = $sFrmtSP;
    }
  }
?>

La diferencia del Script en PHP con el generado en JSP es que las variables miembros de la clase deben tener valores constantes, no tener valores de variables miembros o el resultado de operaciones de variables miembros, sin importar que ese resultado sea producto de variables con valores constantes.
Para construir o darle el valor a $StartFile, se implementó un nuevo método llamado SetStartFile() que no es más que asignarle el mismo valor como se le asigna a StartFile en JSP.
Todos los metodos en PHP cumplen exactamente la misma función que su contraparte en JSP, se puede tomar la explicación que se dió anteriormente, excepto para el constructor RTFFile() en JSP de la clase RTFFile que en PHP es __construct().
ResetFile() Este método es un poco diferente al explicado en JSP porque además debe asignarsele el valor a la variable $StartFile por eso incluye o se invoca el método SetStartFile().

Ahora explicaremos la clase RTFTable

<!-- RTFTable -->
<?php
  class RTFTable {
    private $NumRows = 1;
    private $NumCols = 1;
    private $Cells = array();
    private $BasicFormatCells = array();
    private $OtherFormatCells = array();
    private $MergedVertCells = array();
    private $MergedHorzCells = array();
    private $ElementCells = array();
    private $WideColCells = array();
    private $TablEspMd = 0;
    private $TablPosic = 0;//Position
    private $TablAligH = 0;//Alineacion = Center(Center, Left, Right)
    private $TablEdgeT = 1;//Border Type = Single
    private $TablThick = 1; //Grosor
    private $TablColor = 1;
    private $CellAligV = 0;//Alineacion Vertical = Top(Top, Center, Botton)
    private $CellEdgeT = 1;//Border Type = Single
    private $CellThick = 1; //Grosor
    private $CellColor;
    private $WideCols = 1200;
    private $BasicFormat = "";
    private $OtherFormat = "";

    private $aBorde = array(
      '\\brdrnone', //No border.
      '\\brdrs', //Single-thickness border.
      '\\brdrth', //Double-thickness border.
      '\\brdrsh', //Shadowed border.
      '\\brdrdb', //Double border.
      '\\brdrdot', // Dotted border.
      '\\brdrdash', //Dashed border.
      '\\brdrinset', //Inset border.
      '\\brdroutset'  //Outset border.
    );//Arreglo de Tipos de Borde

    private $aAlign = array(
      "",//  Dejar Igual
      "\\qc",//  Centrar
      "\\ql",//  Izquierda
      "\\qr",//  Derecha
      "\\qj",//  Justificar
      "\\qd" //  Distribuir
    );//Tipo De Alineación Horizontal de Texto

    private $aAliHT = array(
      '\\trqc', //Centers a table row with respect to its containing column.
      '\\trql', //Left-justifies a table row with respect to its containing column.
      '\\trqr'  //Right-justifies a table row with respect to its containing column.
    );//Tipo De Alineación Horizontal de Tabla

    private $aAliVC = array(
      "\\clvertalt", //Text is top-aligned in cell (the default).
      "\\clvertalc", //Text is centered vertically in cell.
      "\\clvertalb"  //Text is bottom-aligned in cell.
    );//Tipo De Alineación Vertical de Celda

    private $aMrgVC = array(
      "", //Ninguna Mezcla.
      "\\clvmgf", //The first cell in a range of table cells to be vertically merged
      "\\clvmrg"  //Contents of the table cell are vertically merged with those of the preceding cell
    );//Tipo De Unión Vertical de Celda

    public function __construct($NumCols, $NumRows) {
      $this->SetRowsCols($NumCols, $NumRows);
    }

    public function SetRowsCols($NumCols, $NumRows) {
      $this->NumRows=$NumRows;
      $this->NumCols=$NumCols;
      $this->Cells[$this->NumCols][$this->NumRows];
      $this->BasicFormatCells[$this->NumCols][$this->NumRows];
      $this->OtherFormatCells[$this->NumCols][$this->NumRows];
      $this->MergedVertCells[$this->NumCols][$this->NumRows];
      $this->MergedHorzCells[$this->NumCols][$this->NumRows];
      $this->ElementCells[$this->NumCols][$this->NumRows];
      $this->WideColCells[$this->NumCols];
      for($i = 0; $i < $this->NumCols;$i++){
        for($j = 0; $j < $this->NumRows;$j++){
          $this->Cells[$i][$j] = "";
          $this->BasicFormatCells[$i][$j] = "";
          $this->OtherFormatCells[$i][$j] = "";
          $this->MergedVertCells[$i][$j] = 0;
          $this->MergedHorzCells[$i][$j] = 0;
          $this->ElementCells[$i][$j] = 0;
        }
        $this->WideColCells[$i] = 0;
      }
    }

    public function SetFormatTable($EspMd,$Posic,$AligH,$EdgeT,$Thick,$Color) {
      $this->TablEspMd = $EspMd;
      $this->TablPosic = $Posic;
      $this->TablAligH = $AligH;
      $this->TablEdgeT = $EdgeT;
      $this->TablThick = $Thick;
      $this->TablColor = $Color;
    }

    private function GetHeaderTable() {
      $sEspMd = "\\trgaph".$this->TablEspMd;
      $sPosic = "\\trleft".$this->TablPosic;
      global $aAliHT;
      $sHdT = "\n\\par\\ltrrow\\trowd".$sEspMd.$sPosic.$this->aAliHT[$this->TablAligH];
      global $aBorde;
      $sBorde = ($this->TablEdgeT==0)?"":$this->aBorde[$this->TablEdgeT];//Tipo de Borde
      $sHdT = ($this->TablEdgeT==0)?$sHdT." \n":$sHdT."\\trhdr \n";
      $sGrosr = ($this->TablThick==0)?"":"\\brdrw".$this->TablThick;
      $sColor = ($this->TablColor==0)?"":"\\brdrcf".$this->TablColor;
      //BordesDeTabla
      $sTop = "\\trbrdrt".$sBorde.$sGrosr.$sColor." ";//Table row border top
      $sBot = "\\trbrdrb".$sBorde.$sGrosr.$sColor." ";//Table row border bottom
      $sLft = "\\trbrdrl".$sBorde.$sGrosr.$sColor." ";//Table row border left
      $sRgt = "\\trbrdrr".$sBorde.$sGrosr.$sColor." ";//Table row border right
      $sHHz = "\\trbrdrh".$sBorde.$sGrosr.$sColor." ";//Table row border horizontal (inside).
      $sHVt = "\\trbrdrv".$sBorde.$sGrosr.$sColor." ";//Table row border vertical (inside).
      $sTablIH = $sHdT.$sTop.$sLft.$sBot.$sRgt."\n".$sHHz.$sHVt."\n";
      return $sTablIH;
    }

    private function SetNewRowTable() {
      $sEspMd = "\\trgaph".$this->TablEspMd;
      $sPosic = "\\trleft".$this->TablPosic;
      global $aAliHT;
      $sHdT = "\n\\ltrrow\\trowd".$sEspMd.$sPosic.$this->aAliHT[$this->TablAligH];
      $sHdT = $this->GetEndTable().$sHdT." \n";
      return $sHdT;
    }

    private function GetFooterTable() {
      //Fin de Cabecera de Tabla;
      $sTablFH = "\n\\pard\\intbl\\pard\\plain \n";
      return $sTablFH;
    }

    public function SetFormatCellsTable($AligV,$EdgeT,$Thick,$Color) {
      $this->CellAligV = $AligV;
      $this->CellEdgeT = $EdgeT;
      $this->CellThick = $Thick;
      $this->CellColor = $Color;
    }

    public function SetWideColsTable($WideCols) {
      $this->WideCols = $WideCols;
      for($i = 0; $i<$this->NumCols;$i++){
        $this->WideColCells[$i] = $this->WideCols;
      }
    }

    public function SetWideColTable($Col,$WideCols) {
      if($Col < $this->NumCols){
        $this->WideColCells[$Col] = $WideCols;
      }
    }

    public function SetBasicFormatTextTable($Align, $CFrnt, $CFond, $Fuente, $Talla) {
      //Formatos Necesarios
      $sCFrnt = "\\cf".$CFrnt;
      $sCFond = "\\highlight".$CFond;
      $sFuente = "\\f".$Fuente;
      $sTalla = "\\fs".(2*$Talla);
      $this->BasicFormat = $this->aAlign[$Align].$sCFrnt.$sCFond.$sFuente.$sTalla."\n";
    }

    public function SetOtherFormatTextTable($Negrt,$Italc,$Sbryd) {
      //Aplicar o Quitar Formatos Especiales
      $sNegrt = ($Negrt==0)?"\\b0":"\\b";//  Negrita
      $sItalc = ($Italc==0)?"\\i0":"\\i";//  Itálica
      $sSbryd = ($Sbryd==0)?"\\ul0":"\\ul";// Subrayar
      $sFrmtSP = $sNegrt.$sItalc.$sSbryd."\n";
      $this->OtherFormat = $sFrmtSP;
    }

    public function SetBasicFormatTextCell($Col, $Row, $Align, $CFrnt, $CFond, $Fuente, $Talla) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $sCFrnt = "\\cf".$CFrnt;
        $sCFond = "\\highlight".$CFond;
        $sFuente = "\\f".$Fuente;
        $sTalla = "\\fs".(2*$Talla);
        $this->BasicFormatCells[$Col][$Row] = $this->aAlign[$Align].$sCFrnt.$sCFond.$sFuente.$sTalla."\n";
      }
    }

    public function SetOtherFormatTextCell($Col, $Row, $Negrt,$Italc,$Sbryd) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $sNegrt = ($Negrt==0)?"\\b0":"\\b";//  Negrita
        $sItalc = ($Italc==0)?"\\i0":"\\i";//  Itálica
        $sSbryd = ($Sbryd==0)?"\\ul0":"\\ul";// Subrayar
        $this->OtherFormatCells[$Col][$Row] = $sNegrt.$sItalc.$sSbryd."\n";
      }
    }

    public function SetMergeVertCell($Col, $Row, $Value) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $this->MergedVertCells[$Col][$Row] = $Value;
      }
    }

    public function SetMergeHorzCell($Col, $Row, $Value) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $this->MergedHorzCells[$Col][$Row] = $Value;
      }
    }

    public function SetElementCell($Col, $Row, $Value) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $this->Cells[$Col][$Row] = $Value;
        $this->ElementCells[$Col][$Row] = 1;
      }
    }

    public function SetTextCell($Col, $Row, $Value) {
      if($Col<$this->NumCols && $Row<$this->NumRows){
        $this->Cells[$Col][$Row] = $Value;
        $this->ElementCells[$Col][$Row] = 0;
      }
    }

    private function GetHeaderCell($Col, $Row){
      $sBorde = $this->CellEdgeT==0?"":$this->aBorde[$this->CellEdgeT];
      $sGrosr = $this->CellThick==0?"":"\\brdrw".$this->TablThick;
      $sColor = $this->CellColor==0?"":"\\brdrcf".$this->CellColor;
      $sTop = "\\clbrdrt".$sBorde.$sGrosr.$sColor." ";//Top table cell border
      $sBot = "\\clbrdrb".$sBorde.$sGrosr.$sColor." ";//Bottom table cell border
      $sLft = "\\clbrdrl".$sBorde.$sGrosr.$sColor." ";//Left row border left
      $sRgt = "\\clbrdrr".$sBorde.$sGrosr.$sColor." ";//Right table cell border
      $Width = 0;
      for ($i = 0; $i <= $Col;$i++){
        if ($this->WideColCells[$i]==0){
          $Width += $this->WideCols;
        } else {
          $Width += $this->WideColCells[$i];
        }
      }
      if ($this->MergedHorzCells[$Col][$Row]==1){
        for($i = $Col; $i < $this->NumCols;$i++){
          if($this->MergedHorzCells[$i][$Row]==2){
            if ($this->WideColCells[$i]==0){
              $Width += $this->WideCols;
            } else {
              $Width += $this->WideColCells[$i];
            }
          }
          if($this->MergedHorzCells[$i][$Row]==0) {
            $i = $this->NumRows;
          }
        }
      }
      $sLimit = "\\cellx".$Width." \n";
      $Merged = $this->MergedVertCells[$Col][$Row];
      $sCeldaH = $this->aMrgVC[$Merged].$this->aAliVC[$this->CellAligV].$sTop.$sLft.$sBot.$sRgt.$sLimit;
      if($this->MergedHorzCells[$Col][$Row]==2){
        $sCeldaH = "";
      }
      return $sCeldaH;
    }

    private function GetTextCell($Col, $Row) {
      $TextFormattedCell = "\\pard\\plain\\intbl\\ltrpar";

      if (!$this->BasicFormatCells[$Col][$Row]=="")
        $TextFormattedCell .= $this->BasicFormatCells[$Col][$Row];
      else
        $TextFormattedCell .= $this->BasicFormat;

      if (!$this->OtherFormatCells[$Col][$Row]=="")
        $TextFormattedCell .= $this->OtherFormatCells[$Col][$Row];
      else
        $TextFormattedCell .= $this->OtherFormat;
      $TextFormattedCell .= $this->Cells[$Col][$Row];
      $TextFormattedCell .= "\\cell \n";
      if($this->MergedHorzCells[$Col][$Row]==2){
        $TextFormattedCell = "";
      }
      return $TextFormattedCell;
    }

    private function GetElementCell($Col, $Row) {
      $TextFormattedCell = "\\pard\\plain\\intbl\\ltrpar";
      $TextFormattedCell .= $this->Cells[$Col][$Row];
      $TextFormattedCell .= "\\cell \n";
      if($this->MergedHorzCells[$Col][$Row]==2){
        $TextFormattedCell = "";
      }
      return $TextFormattedCell;
    }

    private function GetEndTable() {
      $sTablFF = "\n\\row\\pard \n";
      return $sTablFF;
    }

    public function GetTable(){
      $StringTable = "";
      if($this->NumRows>0){
        $StringTable .= $this->GetHeaderTable();
        for($i = 0; $i<$this->NumCols;$i++){
          $StringTable .= $this->GetHeaderCell($i,0);
        }
        $StringTable .= $this->GetFooterTable();

        for($i = 0; $i<$this->NumCols;$i++){
          if ($this->ElementCells[$i][0]==0){
            $StringTable .= $this->GetTextCell($i,0);
          } else {
            $StringTable .= $this->GetElementCell($i,0);
          }
        }

        if($this->NumRows>1){
          for ($j = 1; $j<$this->NumRows;$j++){
            $StringTable .= $this->SetNewRowTable();
            for($i = 0; $i<$this->NumCols;$i++){
              $StringTable .= $this->GetHeaderCell($i,$j);
            }
            $StringTable .= $this->GetFooterTable();

            for($i = 0; $i<$this->NumCols;$i++){
              if ($this->ElementCells[$i][$j]==0){
                $StringTable .= $this->GetTextCell($i,$j);
              } else {
                $StringTable .= $this->GetElementCell($i,$j);
              }
            }
          }
        }
        $StringTable .= $this->GetEndTable();
      }
      return $StringTable;
    }
  }
?>

RTFTable es una clase que nos permite construir una tabla que se insertará como un elemento en un archivo RTF, es decir, un objeto de la clase RTFFile.
Los miembros de la clase son:
$NumRows Número de Filas de la tabla, predefinida a 1.
$NumCols Número de Columnas de la tabla, predefinida a 1.
$Cells Es una matriz o arreglo bidimensional que almacenará el contenido de cada celda.
$BasicFormatCells Es una matriz que almacenará opcionalmente el formato básico de una celda en particular.
$OtherFormatCells Es una matriz similar a la anterior, la diferencia es que almacena opcionalmente el formato opcional del una celda de manera particular.
$MergedVertCells Matriz que permite almacenar las combinaciones o mezclas de celdas de manera vertical establecidas.
$MergedHorzCells Matriz que permite almacenar las combinaciones o mezclas de celdas de manera horizontal establecidas.
$ElementCells Matriz que almacena identicadores de Texto o Elemento almacenados en la matriz $Cells.
$WideColCells Es un arreglo unidimensional que almacena los anchos de las columnas, también es opcional.

$TablEspMd Espacio medio en twips entre las celdas de una fila de una tabla.
$TablPosic Posición en twips del borde izquierdo de la tabla con respecto a la columna de la izquierda. ver \trleftN en documentación RTF.
$TablAligH Alineación horizontal de la tabla.
$TablEdgeT Almacena el tipo de borde de la tabla.
$TablThick ALmacena el grosor de la tabla.
$TablColor Guarda el color de la tabla, debe tenerse en cuenta que este valor será tomado del archivo RTF, que es de tipo RTFFile.

$CellAligV Alineación vertical en la celda.
$CellEdgeT Tipo de borde de la celda.
$CellThick Grosor del borde de la celda.
$CellColor Permite establecer el color del borde de la celda.

$WideCols Almacena el ancho genérico de las columnas.
$BasicFormat Guarda el formato básico de texto para todas las celdas, se excluye aquellas celdas que tienen su valor de formato básico particular en la matriz $BasicFormatCells
$OtherFormat Funciona de manera identica a $BasicFormat, solo que almacena el formato opcional.

$aBorde Es un arreglo que almacena los posibles bordes a utilizar en la tabla o en las celdas.
$aAlign Es un arreglo que almacena las posibles alineaciones horizontales aplicables al texto, bien general o por celdas.
$aAliHT Arreglo que almacena las alineaciones horizontales de tabla posibles.
$aAliVC Arreglo que almacena los valores de alineación vertical de contenido de celdas.
$aMrgVC Arreglo que almacena los valores posibles y necesarios para combinar celdas de manera vertical.

__construct($NumCols, $NumRows) Permite crear una instancia de RTFTable, tomando como argumentos $NumCols para el número de columnas y $NumRows para el número de filas y llamando al método SetRowsCols.
SetRowsCols($NumCols, $NumRows) Este método establece el número de Columnas y Filas para la tabla en cuestión, establece las dimensiones de las matrices de la clase y las inicializa.
SetFormatTable($EspMd,$Posic,$AligH,$EdgeT,$Thick,$Color) Permite asignarles los valores a las variables relacionadas con los parámetros de las tablas.
GetHeaderTable() Genera el encabezado de la tabla según los parámetros establecidos con SetFormatTable.
SetNewRowTable() Permite insertar o crear una nueva fila teniendo en cuenta algunos parámetros establecidos para la tabla con el método SetFormatTable.
GetFooterTable() Retorna una cadena que indica la declaración de una fila de una tabla.
SetFormatCellsTable($AligV,$EdgeT,$Thick,$Color) Establece los valores a las variables que determinan los parámetros de las celdas de la Tabla.
SetWideColsTable($WideCols) Permite asignarle a todas las columnas de la tabla un único valor según el argumento $WideCols para el ancho de cada una de ellas.
SetWideColTable($Col,$WideCols) Permite asignarle a una columna en particular indicada por el argumento $Col el valor de ancho $WideCols.
SetBasicFormatTextTable($Align, $CFrnt, $CFond, $Fuente, $Talla) Establece el formato básico de texto para todas las celdas de la tabla, excepto para aquellas celdas que se les asigne un formato básico particular.
SetOtherFormatTextTable($Negrt,$Italc,$Sbryd) Establece el formato opcional de texto para todas las celdas de la tabla, excepto para aquellas celdas que se les asigne un formato opcional particular.

SetBasicFormatTextCell($Col, $Row, $Align, $CFrnt, $CFond, $Fuente, $Talla) Establece el formato básico de texto para una celda en particular indicada según los argumentos $Col y $Row y se almacena en la matriz BasicFormatCells.
SetOtherFormatTextCell($Col, $Row, $Negrt,$Italc,$Sbryd) Establece el formato opcional de texto para una celda en particular indicada según los argumentos $Col y $Row y se almacena en la matriz OtherFormatCells.
SetMergeVertCell($Col, $Row, $Value) Permite establecer la mezcla de manera vertical de una celda indicada por $Col y $Row y su manera según el argumento $Value.
SetMergeHorzCell($Col, $Row, $Value) Permite establecer la mezcla de manera horizontal de una celda indicada por $Col y $Row y su manera según el argumento $Value.
SetElementCell($Col, $Row, $Value) Dispone un elemento para una celda, éste se almacena en la matriz Cells, indicándose con un “1” que es de tipo elemento en la matriz ElementCells.
SetTextCell($Col, $Row, $Value) Dispone el texto para una celda, su valor se almacenará en la matriz Cells, indicándose con un “0” que es de tipo texto en la matriz ElementCells.
GetHeaderCell($Col, $Row) Retorna la cabecera de una celda, es con este método que se crea la celda, teniendo en cuenta si es mezclada verical u horizontal, borde, color, entre otros parámetros.
GetTextCell($Col, $Row) Retorna el texto de una celda, con el formato básico y formato opcional, teniendo en cuenta de que estos formatos son específicos para la celda indicada por los argumentos $Col y $Row o genéricos; también si existe la mezcla horizontal.
GetElementCell($Col, $Row) Funciona de manera similar a GetTextCell la diferencia es que no se aplican los formatos básicos y opcionales que se le aplican al texto, también tiene en cuenta si debe aplicarse la mezcla horizontal.

GetEndTable() Retorna una cadena indicando el fin de la de tabla.
GetTable() Retorna la tabla completamente, es decir, formato de tabla, formato de celdas y contenido de celas, mezclas verticales y horizontales.

Script JSP (RTF.jsp)
Ahora miremos el código de la clase RTFTable para JSP

<!-- RTFTable -->
<%!
  public class RTFTable {
    private int NumRows = 1;
    private int NumCols = 1;
    private String[][] Cells;
    private String[][] BasicFormatCells;
    private String[][] OtherFormatCells;
    private Integer[][] MergedVertCells;
    private Integer[][] MergedHorzCells;
    private Integer[][] ElementCells;
    private Integer[] WideColCells;
    private int TablEspMd = 0;
    private int TablPosic = 0;//Position
    private int TablAligH = 0;//Alineacion = Center(Center, Left, Right)
    private int TablEdgeT = 1;//Border Type = Single
    private int TablThick = 1; //Grosor
    private int TablColor = 1;
    private int CellAligV = 0;//Alineacion Vertical = Top(Top, Center, Botton)
    private int CellEdgeT = 1;//Border Type = Single
    private int CellThick = 1; //Grosor
    private int CellColor;
    private int WideCols = 1200;
    private String BasicFormat = "";
    private String OtherFormat = "";

    private String[] aBorde = {
      "\\brdrnone", //No border.
      "\\brdrs", //Single-thickness border.
      "\\brdrth", //Double-thickness border.
      "\\brdrsh", //Shadowed border.
      "\\brdrdb", //Double border.
      "\\brdrdot", // Dotted border.
      "\\brdrdash", //Dashed border.
      "\\brdrinset", //Inset border.
      "\\brdroutset"  //Outset border.
    };//Arreglo de Tipos de Borde

    private String[] aAlign = {
      "",//  Dejar Igual
      "\\qc",//  Centrar
      "\\ql",//  Izquierda
      "\\qr",//  Derecha
      "\\qj",//  Justificar
      "\\qd" //  Distribuir
    };//Tipo De Alineación Horizontal de Texto

    private String[] aAliHT = {
      "\\trqc", //Centers a table row with respect to its containing column.
      "\\trql", //Left-justifies a table row with respect to its containing column.
      "\\trqr"  //Right-justifies a table row with respect to its containing column.
    };//Tipo De Alineación Horizontal de Tabla

    private String[] aAliVC = {
      "\\clvertalt", //Text is top-aligned in cell (the default).
      "\\clvertalc", //Text is centered vertically in cell.
      "\\clvertalb"  //Text is bottom-aligned in cell.
    };//Tipo De Alineación Vertical de Celda

    private String[] aMrgVC = {
      "", //Ninguna Mezcla.
      "\\clvmgf", //The first cell in a range of table cells to be vertically merged
      "\\clvmrg"  //Contents of the table cell are vertically merged with those of the preceding cell
    };//Tipo De Unión Vertical de Celda

    RTFTable(int NumCols, int NumRows) {
      SetRowsCols(NumCols,NumRows);
    }

    private void SetRowsCols(int NumCols, int NumRows) {
      this.NumCols = NumCols;
      this.NumRows = NumRows;
      this.Cells = new String[this.NumCols][this.NumRows];
      this.BasicFormatCells = new String[this.NumCols][this.NumRows];
      this.OtherFormatCells = new String[this.NumCols][this.NumRows];
      this.MergedVertCells = new Integer[this.NumCols][this.NumRows];
      this.MergedHorzCells = new Integer[this.NumCols][this.NumRows];
      this.ElementCells = new Integer[this.NumCols][this.NumRows];
      this.WideColCells = new Integer[this.NumCols];
      for(int i = 0; i < this.NumCols;i++){
        for(int j = 0; j < this.NumRows;j++){
          this.Cells[i][j] = "";
          this.BasicFormatCells[i][j] = "";
          this.OtherFormatCells[i][j] = "";
          this.MergedVertCells[i][j] = 0;
          this.MergedHorzCells[i][j] = 0;
          this.ElementCells[i][j] = 0;
        }
        this.WideColCells[i] = 0;
      }
    }

    public void SetFormatTable(int EspMd,int Posic,int AligH,int EdgeT,int Thick,int Color) {
      this.TablEspMd = EspMd;
      this.TablPosic = Posic;
      this.TablAligH = AligH;
      this.TablEdgeT = EdgeT;
      this.TablThick = Thick;
      this.TablColor = Color;
    }

    private String GetHeaderTable() {
      String sEspMd = "\\trgaph"+String.valueOf(this.TablEspMd);
      String sPosic = "\\trleft"+String.valueOf(this.TablPosic);//
      String sHdT = "\n\\par\\ltrrow\\trowd"+sEspMd+sPosic+this.aAliHT[this.TablAligH];
      String sBorde = this.TablEdgeT==0?"":this.aBorde[this.TablEdgeT];//Tipo de Borde
      sHdT = this.TablEdgeT==0?sHdT+" \n":sHdT+"\\trhdr \n";
      String sGrosr = this.TablThick==0?"":"\\brdrw"+String.valueOf(this.TablThick);
      String sColor = this.TablColor==0?"":"\\brdrcf"+String.valueOf(this.TablColor);
      //BordesDeTabla
      String sTop = "\\trbrdrt"+sBorde+sGrosr+sColor+" ";//Table row border top
      String sBot = "\\trbrdrb"+sBorde+sGrosr+sColor+" ";//Table row border bottom
      String sLft = "\\trbrdrl"+sBorde+sGrosr+sColor+" ";//Table row border left
      String sRgt = "\\trbrdrr"+sBorde+sGrosr+sColor+" ";//Table row border right
      String sHHz = "\\trbrdrh"+sBorde+sGrosr+sColor+" ";//Table row border horizontal (inside).
      String sHVt = "\\trbrdrv"+sBorde+sGrosr+sColor+" ";//Table row border vertical (inside).
      String sTablIH = sHdT+sTop+sLft+sBot+sRgt+"\n"+sHHz+sHVt+"\n";
      return sTablIH;
    }

    private String SetNewRowTable() {
      String sEspMd = "\\trgaph"+String.valueOf(this.TablEspMd);
      String sPosic = "\\trleft"+String.valueOf(this.TablPosic);//
      String sHdT = "\n\\ltrrow\\trowd"+sEspMd+sPosic+this.aAliHT[this.TablAligH];
      sHdT = this.GetEndTable() + sHdT+" \n";
      return sHdT;
    }

    private String GetFooterTable() {
      //Fin de Cabecera de Tabla;
      String sTablFH = "\n\\pard\\intbl\\pard\\plain \n";
      return sTablFH;
    }

    public void SetFormatCellsTable(int AligV,int EdgeT,int Thick,int Color) {
      this.CellAligV = AligV;
      this.CellEdgeT = EdgeT;
      this.CellThick = Thick;
      this.CellColor = Color;
    }

    public void SetWideColsTable(int WideCols) {
      this.WideCols = WideCols;
      for(int i = 0; i<this.NumCols;i++){
        this.WideColCells[i] = WideCols;
      }
    }

    public void SetWideColTable(int Col,int WideCols) {
      if(Col < this.NumCols){
        this.WideColCells[Col] = WideCols;
      }
    }

    public void SetBasicFormatTextTable(int Align, int CFrnt, int CFond, int Fuente, int Talla) {
      String sCFrnt = "\\cf"+String.valueOf(CFrnt);
      String sCFond = "\\highlight"+String.valueOf(CFond);
      String sFuente = "\\f"+String.valueOf(Fuente);
      String sTalla = "\\fs"+String.valueOf(2*Talla);
      this.BasicFormat = this.aAlign[Align]+sCFrnt+sCFond+sFuente+sTalla+"\n";
    }

    public void SetOtherFormatTextTable(int Negrt, int Italc, int Sbryd) {
      String sNegrt = Negrt==0?"\\b0":"\\b";//  Negrita
      String sItalc = Italc==0?"\\i0":"\\i";//  Itálica
      String sSbryd = Sbryd==0?"\\ul0":"\\ul";// Subrayar
      this.OtherFormat = sNegrt+sItalc+sSbryd+"\n";
    }

    public void SetBasicFormatTextCell(int Col, int Row, int Align, int CFrnt, int CFond, int Fuente, int Talla) {
      if(Col<this.NumCols && Row<this.NumRows){
        String sCFrnt = "\\cf"+String.valueOf(CFrnt);
        String sCFond = "\\highlight"+String.valueOf(CFond);
        String sFuente = "\\f"+String.valueOf(Fuente);
        String sTalla = "\\fs"+String.valueOf(2*Talla);
        this.BasicFormatCells[Col][Row] = this.aAlign[Align]+sCFrnt+sCFond+sFuente+sTalla+"\n";
      }
    }

    public void SetOtherFormatTextCell(int Col, int Row, int Negrt, int Italc, int Sbryd) {
      if(Col<this.NumCols && Row<this.NumRows){
        String sNegrt = Negrt==0?"\\b0":"\\b";//  Negrita
        String sItalc = Italc==0?"\\i0":"\\i";//  Itálica
        String sSbryd = Sbryd==0?"\\ul0":"\\ul";// Subrayar
        this.OtherFormatCells[Col][Row] = sNegrt+sItalc+sSbryd+"\n";
      }
    }

    public void SetMergeVertCell(int Col, int Row,int Value) {
      if(Col<this.NumCols && Row<this.NumRows){
        this.MergedVertCells[Col][Row] = Value;
      }
    }

    public void SetMergeHorzCell(int Col, int Row,int Value) {
      if(Col<this.NumCols && Row<this.NumRows){
        this.MergedHorzCells[Col][Row] = Value;
      }
    }

    public void SetElementCell(int Col, int Row,String Value) {
      if(Col<this.NumCols && Row<this.NumRows){
        this.Cells[Col][Row] = Value;
        this.ElementCells[Col][Row] = 1;
      }
    }

    public void SetTextCell(int Col, int Row,String Value) {
      if(Col<this.NumCols && Row<this.NumRows){
        this.Cells[Col][Row] = Value;
        this.ElementCells[Col][Row] = 0;
      }
    }

    private String GetHeaderCell(int Col, int Row){
      String sBorde = this.CellEdgeT==0?"":this.aBorde[this.CellEdgeT];
      String sGrosr = this.CellThick==0?"":"\\brdrw"+String.valueOf(this.CellThick);
      String sColor = this.CellColor==0?"":"\\brdrcf"+String.valueOf(this.CellColor);
      String sTop = "\\clbrdrt"+sBorde+sGrosr+sColor+" ";//Top table cell border
      String sBot = "\\clbrdrb"+sBorde+sGrosr+sColor+" ";//Bottom table cell border
      String sLft = "\\clbrdrl"+sBorde+sGrosr+sColor+" ";//Left row border left
      String sRgt = "\\clbrdrr"+sBorde+sGrosr+sColor+" ";//Right table cell border
      int Width = 0;
      for (int i = 0; i <= Col;i++){
        if (this.WideColCells[i]==0){
          Width += this.WideCols;
        } else {
          Width += this.WideColCells[i];
        }
      }
      if (this.MergedHorzCells[Col][Row]==1){
        for(int i = Col; i < this.NumCols;i++){
          if(this.MergedHorzCells[i][Row]==2){
            if (this.WideColCells[i]==0){
              Width += this.WideCols;
            } else {
              Width += this.WideColCells[i];
            }
          }
          if(this.MergedHorzCells[i][Row]==0) {
            i = this.NumRows;
          }
        }
      }
      String sLimit = "\\cellx"+Width+" \n";
      int Merged = this.MergedVertCells[Col][Row];
      String sCeldaH = this.aMrgVC[Merged]+this.aAliVC[this.CellAligV]+sTop+sLft+sBot+sRgt+sLimit;
      if(this.MergedHorzCells[Col][Row]==2){
        sCeldaH = "";
      }
      return sCeldaH;
    }

    private String GetTextCell(int Col, int Row) {
      String TextFormattedCell = "\\pard\\plain\\intbl\\ltrpar";

      if (!this.BasicFormatCells[Col][Row].isEmpty())
        TextFormattedCell += this.BasicFormatCells[Col][Row];
      else
        TextFormattedCell += this.BasicFormat;

      if (!this.OtherFormatCells[Col][Row].isEmpty())
        TextFormattedCell += this.OtherFormatCells[Col][Row];
      else
        TextFormattedCell += this.OtherFormat;
      TextFormattedCell += this.Cells[Col][Row];
      TextFormattedCell += "\\cell \n";
      if(this.MergedHorzCells[Col][Row]==2){
        TextFormattedCell = "";
      }
      return TextFormattedCell;
    }

    private String GetElementCell(int Col, int Row) {
      String TextFormattedCell = "\\pard\\plain\\intbl\\ltrpar";
      TextFormattedCell += this.Cells[Col][Row];
      TextFormattedCell += "\\cell";
      if(this.MergedHorzCells[Col][Row]==2){
        TextFormattedCell = "";
      }
      return TextFormattedCell;
    }

    private String GetEndTable() {
      String sTablFF = "\n\\row\\pard \n";
      return sTablFF;
    }

    public String GetTable(){
      String StringTable = "";
      if(this.NumRows>0){
        StringTable += this.GetHeaderTable();
        for(int i = 0; i<this.NumCols;i++){
          StringTable += this.GetHeaderCell(i,0);
        }
        StringTable += this.GetFooterTable();

        for(int i = 0; i<this.NumCols;i++){
          if (this.ElementCells[i][0]==0){
            StringTable += this.GetTextCell(i,0);
          } else {
            StringTable += this.GetElementCell(i,0);
          }
        }
        if(this.NumRows>1){
          for (int j = 1; j<this.NumRows;j++){
            StringTable += this.SetNewRowTable();
            for(int i = 0; i<this.NumCols;i++){
              StringTable += this.GetHeaderCell(i,j);
            }
            StringTable += this.GetFooterTable();
            for(int i = 0; i<this.NumCols;i++){
              if (this.ElementCells[i][j]==0){
                StringTable += this.GetTextCell(i,j);
              } else {
                StringTable += this.GetElementCell(i,j);
              }
            }
          }
        }
        StringTable += this.GetEndTable();
      }
      return StringTable;
    }
  }
%>

Vemos que conceptualmente las variables y métodos de JSP son iguales a los de PHP por eso las explicaciones son iguales a las anteriormente dadas, teniendo en cuenta lo mismo para el caso de los métodos de los constructores respectivos RTFTable(int NumCols, int NumRows) en JSP corresponde a __construct($NumCols, $NumRows) en PHP.

Ahora explicaré la clase RTFImage

<!-- RTFImage -->
<%!
  public class RTFImage {
    private String HexImageString = "";

    public RTFImage(String ImageFileName,int[] Frmt,int[] High,int[] Wide) {
      byte[] BytesFile = new byte[(int)(new File(ImageFileName).length())];
      FileInputStream fis;
      try {
        fis = new FileInputStream(ImageFileName);
        fis.read(BytesFile);
        fis.close();
      }
      catch (FileNotFoundException fnfe)
      {System.out.println(fnfe.toString());}
      catch (EOFException eofe)
      {System.out.println(eofe.toString());}
      catch (IOException ioe)
      {System.out.println(ioe.toString());}
      this.ByteStreamImageString(BytesFile,Frmt,High,Wide);
    }

    public RTFImage(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
      this.ByteStreamImageString(ByteStream,Frmt,High,Wide);
    }

    private void ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
      High[0] = 0;
      Wide[0] = 0;
      Frmt[0] = -1;
      this.HexImageString = "Error";
      if ((int)(ByteStream[0]&0xFF)==137 && (int)(ByteStream[1]&0xFF)==80 &&(int)(ByteStream[2]&0xFF)==78){
        Frmt[0] = 1; //PNG
        High[0] = this.Byte2PosInt(ByteStream[22],ByteStream[23]);
        Wide[0] = this.Byte2PosInt(ByteStream[18],ByteStream[19]);
      }
      if ((int)(ByteStream[0]&0xFF)==255 && (int)(ByteStream[1]&0xFF)==216
          &&(int)(ByteStream[2]&0xFF)==255 && (int)(ByteStream[3]&0xFF)==224){
        Frmt[0] = 2; //JPG
        int PosJPG = 2;
        while (PosJPG<ByteStream.length){
          if (String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]).equals("FFC0")){
            High[0] = this.Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
            Wide[0] = this.Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
          }
          PosJPG = PosJPG+2+this.Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
        }
      }
      if (Frmt[0] > 0){
        this.HexImageString = "";
        int Salto = 0;
        for (int i=0;i < ByteStream.length; i++){
          Salto++;
          this.HexImageString += String.format("%02x", ByteStream[i]);
          if (Salto==64){
            this.HexImageString += "\n";
            Salto = 0;
          }
        }
      }
    }

    public String GetHexImage(){
      return this.HexImageString;
    }

    public String GetImage(String ImageString,int Type,int High,int Wide,
          int SclY,int SclX, int AltP,int AncP,int CropL,int CropR,int CropT,int CropB) {
      String RTFImagen = "\n"+"{\\pict";
      String sLibI = "\\";
     switch (Type){
      case 1:
        sLibI = sLibI+"pngblip";
        break;
      case 2:
        sLibI = sLibI+"jpegblip";
        break;
      }
      String sHigh = "\\pich"+String.valueOf(High);
      String sWide = "\\picw"+String.valueOf(Wide);
      String sSclX = "\\picscalex"+String.valueOf(SclY);
      String sSclY = "\\picscaley"+String.valueOf(SclX);
      String sAltP = "\\pichgoal"+String.valueOf(AltP);
      String sAncP = "\\picwgoal"+String.valueOf(AncP);
      String sCrpL = "\\piccropl"+String.valueOf(CropL);
      String sCrpR = "\\piccropr"+String.valueOf(CropR);
      String sCrpT = "\\piccropt"+String.valueOf(CropT);
      String sCrpB = "\\piccropb"+String.valueOf(CropB);
      RTFImagen = RTFImagen+sSclX+sSclY+sCrpL+sCrpR+sCrpT+sCrpB+"\n"+sWide+
              sHigh+sAncP+sAltP+sLibI+"\n"+ImageString+"\n}";
      return RTFImagen;
    }

    private Integer Byte2PosInt(byte Byte08, byte Byte00) {
      return new Integer (((Byte08 & 0xFF) << 8)|((Byte00 & 0xFF) << 0));
    }
  }
%>

HexImageString Es una variable interna que almacena como texto hexadecimal la información de la imagen sea de tipo JPG o PNG.

RTFImage(String ImageFileName,int[] Frmt,int[] High,int[] Wide) Es un constructor de la clase RTFImage, sus argumentos son: ImageFileName (Ruta y nombre del archivo imagen), Frmt es un argumento que será retornado por referencia indicando el tipo de formato en caso de ser válido, High retorna la altura de la imagen por referencia, Wide retorna el ancho de la imagen pasando su valor por referencia. El archivo es leído y si es válido como imagen se representará su contenido de manera hexadecimal en HexImageString apoyándose en el método ByteStreamImageString.
RTFImage(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) Es otro constructor, que difiere en sus argumentos en que en vez de recibir la ruta y nombre del archivo imagen, recibe la información binaria de la imagen, ésta es la misma que se extrae leyendola de un archivo, puede obtenerse también desde una fuente como una base de datos, los demás argumentos son y funcionan exactamente iguales.
ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) Es un método importante ya que se encarga de extraer la información binaria pasada por los constructores antes mencionados, analizarla determinando si corresponde al formato JPG o PNG, extrae las dimensiones y las retorna por los argumentos pasando su valor por referencia.
GetHexImage() Retorna la representación en hexadecimal de la imagen como texto, almacenada en la variable HexImageString.
GetImage(String ImageString,int Type,int High,int Wide,int SclY,int SclX, int AltP,int AncP,int CropL,int CropR,int CropT,int CropB) Es un metodo que retorna la representación de la imagen con los parámetros propios del formato RTF, entre ellos dimensiones, escala, dimensiones preferidas y recortes en sus extremos; que son recibidos como argumentos en conjunto con la representación hexadecimal de la imagen ImageString.
Byte2PosInt(byte Byte08, byte Byte00) Es un método de apoyo que convierte 2 bytes y retorna su correspondiente valor a entero.

Script PHP (RTF.php)

<!-- RTFImage -->
<?php
  class RTFImage {
    private $HexImageString = "";

    public function __construct($ImageFileName,&$Formato,&$High,&$Wide) {
      $fis = fopen($ImageFileName, "rb");
      if ($fis!=false){
        $BytesFile = NULL;
        while (!feof($fis)){
          $BytesFile .= fread($fis, 8192);
        }
        fclose($fis);
        $this->ByteStreamImageString($BytesFile,$Formato,$High,$Wide);
      }else {
        $this->ByteStreamImageString($ImageFileName,$Formato,$High,$Wide);
      }
    }

    public function ByteStreamImageString($ByteStream,&$Formato,&$Alto,&$Ancho) {
      $Alto = 0;
      $Ancho = 0;
      $Formato = -1;
      $this->HexImageString = "Error";
      if (ord($ByteStream[0])==137 && ord($ByteStream[1])==80 && ord($ByteStream[2])==78){
        $Formato = 1; //PNG
        $Alto = $this->Byte2PosInt($ByteStream[22],$ByteStream[23]);
        $Ancho = $this->Byte2PosInt($ByteStream[18],$ByteStream[19]);
      }
      if (ord($ByteStream[0])==255 && ord($ByteStream[1])==216
          && ord($ByteStream[2])==255 && ord($ByteStream[3])==224){
        $Formato = 2; //JPG
        $PosJPG = 2;
        while ($PosJPG<strlen($ByteStream)){
          if (sprintf("%02X%02X", ord($ByteStream[$PosJPG+0]),ord($ByteStream[$PosJPG+1]))=="FFC0"){
            $Alto = $this->Byte2PosInt($ByteStream[$PosJPG+5],$ByteStream[$PosJPG+6]);
            $Ancho = $this->Byte2PosInt($ByteStream[$PosJPG+7],$ByteStream[$PosJPG+8]);
          }
          $PosJPG = $PosJPG+2+$this->Byte2PosInt($ByteStream[$PosJPG+2],$ByteStream[$PosJPG+3]);
        }
      }
      if ($Formato > 0){
        $this->HexImageString = "";
        $Salto = 0;
        for ($i=0;$i < strlen($ByteStream); $i++){
          $Salto++;
          $this->HexImageString .= sprintf("%02x", ord($ByteStream[$i]));
          if ($Salto==64){
            $this->HexImageString .= "\n";
            $Salto = 0;
          }
        }
      }
    }

    public function GetHexImage(){
      return $this->HexImageString;
    }

    public function GetImage($ImageString,$Type,$High,$Wide,$SclY,$SclX,
          $AltP,$AncP,$CropL,$CropR,$CropT,$CropB) {
      $RTFImagen = "\n"."{\\pict";
      $sLibI = "\\";
      switch ($Type){
        case 1:
          $sLibI = $sLibI."pngblip";
          break;
        case 2:
          $sLibI = $sLibI."jpegblip";
          break;
      }
      $sHigh = "\\pich".$High;
      $sAnch = "\\picw".$Wide;
      $sSclX = "\\picscalex".$SclY;
      $sSclY = "\\picscaley".$SclX;
      $sAltP = "\\pichgoal".$AltP;
      $sAncP = "\\picwgoal".$AncP;
      $sCrpL = "\\piccropl".$CropL;
      $sCrpR = "\\piccropr".$CropR;
      $sCrpT = "\\piccropt".$CropT;
      $sCrpB = "\\piccropb".$CropB;
      $RTFImagen = $RTFImagen.$sSclX.$sSclY.$sCrpL.$sCrpR.$sCrpT.$sCrpB."\n".$sAnch.
              $sHigh.$sAncP.$sAltP.$sLibI."\n".$ImageString."\n}";
      return $RTFImagen;
    }

    private function Byte2PosInt($Byte08,$Byte00) {
      return ((ord($Byte08) & 0xFF) << 8)|((ord($Byte00) & 0xFF) << 0);
    }
  }
?>

A diferencia de JSP que los objetos String y arreglo de bytes son diferentes, en PHP no lo son puesto que son tratados como cadenas de texto; es por ello que la ruta de un archivo y el arreglo de bytes son del mismo tipo y de esta manera no hay formas de diferenciarlos sino por el contenido.
En JSP hubo dos constructores, mientras que en PHP solo hay uno, que es __construct($ImageFileName,&$Formato,&$High,&$Wide), este verifica que el argumento $ImageFileName sea una ruta de imagen, de serlo lo lee y carga su contenido en un arreglo de bytes y será tratado por el método ByteStreamImageString; de no ser una ruta de archivo de imagen no se intentará leer sino que se considerará un arreglo de bytes y también será tratado por el método ByteStreamImageString. Los demás métodos son iguales en su propósito.

Publicado en Classes, Java, Java Server Pages, JSP, JSP, Methods, OOP, PHP, PHP, Programming, RTF, Scripts | Etiquetado , , , , , , , , , | 1 Comentario

Subiendo Imágenes y Archivos a MySQL con PHP y JSP y desplegándolos en RTF


En este tutorial vamos a demostrar como através de JSP y PHP subir imágenes y archivos de texto al servidor, insertarlos en bases de datos de MySQL, luego obtenerlos para desplegarlos en archivos tipo RTF.

Como vamos a subir imágenes y archivos de texto probablemente éstos tengan un tamaño considerable, es decir, no tan pequeños. Por lo que debemos hacer algunos cambios en nuestras configuraciones anteriormente detalladas.

Primero tener presente que finalmente los archivos van a ser almacenados en MySQL, esto quiere decir que debemos indicarle eso, através de la modificación del archivo my.ini que se encuentra en el folder de instalación de MySQL, para ello buscamos la entrada [mysqld] y justo debajo le indicamos que el paquete máximo permitido sea de 2MB añadiendo la línea:
max_allowed_packet=2M

Para JSP es suficiente con incluir las librerías commons-fileupload-1.2.2.jar (que viene dentro del archivo commons-fileupload-1.2.2-bin.zip) y commons-io-2.0.1.jar (que viene dentro del archivo commons-io-2.0.1-bin.zip) dentro del folder \lib en la carpeta de instalación de Tomcat.

Para PHP se necesitan hacer unos ajustes en su archivo de configuración php.ini. Dependiendo de la cantidad de archivos a subir y del tamaño de cada uno de ellos, será necesario cambiar las variables post_max_size que inicialmente tiene un valor de 8M y upload_max_filesize que inicialmente tiene un valor de 2M.

Obviamente en algún momento se deberá establecer un tope máximo de subida y es aquí donde esas variables son obligadas. También es necesario considerar los tiempos involucrados en dichas subidas debido al tamaño y ancho de banda disponible para ello.
Por ahora cambiemos estos valores así:
; post_max_size = 8M
post_max_size = 16M y
; upload_max_filesize = 2M
upload_max_filesize = 16M

Teniendo en cuenta que están involucradas las variables en cuanto a demora y duración del Script:
max_execution_time = 30 y
max_input_time = 60.

Ahora ingresamos a MySQL y creamos una base de datos donde podamos hacer las demostraciones del tutorial.
Primero Verificamos las bases de datos de MySQL, aunque este paso es opcional…
SHOW DATABASES;

Luego creamos nuestra base de datos, en mi caso se llamará Empresa
CREATE DATABASE Empresa;

Ahora usamos la Base de datos recien creada y creamos una tabla de prueba llamada Registros.
USE Empresa;
CREATE TABLE Registros (Nombre varchar(30),Salario int(11),
Ingreso DATE,Foto MEDIUMBLOB,Resumen MEDIUMTEXT);

Igualmente como en el proceso de instalación, verificamos los usuarios y sin problemas creamos el nuestro concediéndole los permisos a nuestra base de datos.
GRANT ALL ON Empresa.* TO elusuario@localhost IDENTIFIED BY ‘laclave’;

Con la base de datos creada, la tabla y sus campos y el usuario que permite utilizarla podemos trabajar por medio de los scripts de JSP y de PHP.

Script JSP (Personal.jsp)
Como vamos a trabajar con la subida de archivos a MySQL con commons-fileupload-1.2.2.jar y con commons-io-2.0.1.jar haré un detalle no muy profundo de parte del Script.
Primero la importación de librerías:

<%@ page import="org.apache.commons.fileupload.*" %>
<%@ page import="org.apache.commons.fileupload.servlet.*" %>
<%@ page import="org.apache.commons.fileupload.disk.*" %>
<%@ page import="java.sql.*" %>
<%@ page import="java.util.*" %>
<%@ page import="java.io.*" %>
<%@ include file="RTF.jsp" %>

Las importaciones para org.apache.commons.fileupload son las que nos permiten la gestión de subida de archivos y otros parámetros como campos de formularios, etc.
La importación java.sql obviamente para la gestión de consultas hacia MySQL.
La importación java.util para manejo de iteraciones y la importación java.io lectura y escritura de archivos.
La inclusión del archivo RTF.jsp es para poder hacer uso de funciones inherentes al formato RTF.

Script PHP (Personal.php)
Para el caso de PHP, no es necesario hacer la importación de librerías de esta manera. Solo la inclusión del archivo RTF.php de funciones para RTF.

<?php require("RTF.php"); ?>

Ahora detallo lo referente al código HTML para nuestro formulario que nos permiten ingresar los campos:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title>Registros - <?php print $_SERVER['PHP_SELF']; ?></title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <link rel="shortcut icon" href="BZ.ico" type="image/x-icon" />
  </head>
  <body>
    <form action="<?php print $_SERVER['PHP_SELF']; ?>" method="post" name="FormOperar" enctype="multipart/form-data">
      Nombres y Apellidos: <input type="text" name="tNombre" value="" size="30" /><br/>
      Valor Salario: <input type="text" name="tSalario" value="" size="11" /><br/>
      Fecha Ingreso: <input type="text" name="tIngreso" value="" size="10" /><br/>
      Foto Reciente: <input type="file" name="fFoto" value="" size="60" /><br/>
      Resumen: <input type="file" name="fResumen" value="" size="60" /><br/>
      <input type="submit" name="bCargar" value="Cargar Datos" style="FONT-SIZE: 8pt; FONT-FAMILY: Courier"/><br/>
      <input type="submit" name="bListar" value="Listar Datos" style="FONT-SIZE: 8pt; FONT-FAMILY: Courier"/><br/>
      <input type="submit" name="bBorrar" value="Borrar Datos" style="FONT-SIZE: 8pt; FONT-FAMILY: Courier"/><br/>
    </form>


Como podemos ver además de los campos que nos permitirán ingresar los valores a los campos definidos anteriormente a la base de datos Empresa he dispuesto un ícono distintivo para nuestros Scripts llamado realmente BZ.ico.
Nombres y Apellidos; de tipo Texto
Valor Salario; de tipo numérico
Fecha Ingreso; de tipo Fecha
Foto Reciente; de tipo Binario
Resumen; de tipo Texto.
Además tres botones que nos permitirán: ingresar un registro, listar los registros generando un archivo RTF y borrar los registros.
Con esto cubrimos acciones básicas pero importantes en nuestra base de datos en MySQL.

Script JSP (Personal.jsp)
Para el caso de JSP es similar a PHP solo lo referente al lenguaje en si:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title>Registros - <% out.println(request.getServletPath()); %></title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <link rel="shortcut icon" href="BZ.ico" type="image/x-icon" />
  </head>
  <body>
    <form action="<% out.println(request.getServletPath()); %>" method="post" name="FormOperar" enctype="multipart/form-data">
      Nombres y Apellidos: <input type="text" name="tNombre" value="" size="30" /><br/>
      Valor Salario: <input type="text" name="tSalario" value="" size="11" /><br/>
      Fecha Ingreso: <input type="text" name="tIngreso" value="" size="10" /><br/>
      Foto Reciente: <input type="file" name="fFoto" value="" size="60" /><br/>
      Resumen: <input type="file" name="fResumen" value="" size="60" /><br/>
      <input type="submit" name="bCargar" value="Cargar Datos" style="FONT-SIZE: 8pt; FONT-FAMILY: Courier"/><br/>
      <input type="submit" name="bListar" value="Listar Datos" style="FONT-SIZE: 8pt; FONT-FAMILY: Courier"/><br/>
      <input type="submit" name="bBorrar" value="Borrar Datos" style="FONT-SIZE: 8pt; FONT-FAMILY: Courier"/><br/>
    </form>


Ahora la parte de captura de los campos de nuestro formulario:

<%
      if(ServletFileUpload.isMultipartContent(request)){
        ServletFileUpload SFileUpload = new ServletFileUpload(new DiskFileItemFactory());
        Iterator iter = null;
        Hashtable Parameters = new Hashtable();
        try{
          iter = SFileUpload.parseRequest(request).iterator();
          FileItem FItem = null;
          while(iter.hasNext()){
            FItem = (FileItem)iter.next();
            if (FItem.isFormField() ){
              Parameters.put(FItem.getFieldName(), FItem.getString());
            } else {
              if (FItem.getFieldName().equals("fFoto")){
                Parameters.put(FItem.getFieldName(), FItem.getInputStream());
              }
              if (FItem.getFieldName().equals("fResumen")){
                Parameters.put(FItem.getFieldName(), FItem.getString("ISO-8859-1"));
              }
            }
          }
        }
        catch(FileUploadException e){ out.println(e.toString()); }

Lo que hace el Script anterior es crear un objeto con el que podamos obtener no solo los parámetros “básicos” del formulario de HTML, sino los archivos para los campos “input” de tipo “File”. Poniéndolos en un HashTable para su posterior uso, haciéndo obviamente una discriminación entre ellos.

Script PHP (Personal.php)
Ahora creamos la conexión a MySQL que nos permita realizar la opción según el botón presionado en el formulario. Téngase en cuenta que los parámetros para la base de datos Empresa es la misma que se realizó anteriormente.

<?php
$host = "localhost";
$User = "elusuario";
$Pass = "laclave";
$DB = "Empresa";
$Enlace = new mysqli($host,$User,$Pass,$DB);
if ($Enlace->connect_error) {
printf ("Connect Error: (%d) %s",$Enlace->connect_errno,$Enlace->connect_error);
exit();
}

Script JSP (Personal.jsp)

        String host = "localhost";
        String User = "elusuario";
        String Pass = "laclave";
        String DB = "Empresa";
        try { Class.forName("com.mysql.jdbc.Driver"); }
        catch (ClassNotFoundException e) { out.println(e.toString()); }
        Connection Conexion = null;
        Statement Enunciado = null;
        ResultSet Resultado = null;
        PreparedStatement PE = null;
        try{ Conexion = DriverManager.getConnection("jdbc:mysql://"+host+"/"+DB,User,Pass); }
        catch (SQLException e) { out.println(e.toString()); }

Como se puede notar no es mucha la diferencia conceptualmente hablando, solo los objetos de los que posteriormente tendremos que hacer uso para nuestros objetivos.

Script PHP (Personal.php)
Ahora demostraremos el proceso de Inserción de un registro a la base de datos Empresa

      if (isset($_POST['bCargar'])){
        $Enunciado = $Enlace->prepare("INSERT INTO Registros (Nombre,Salario,Ingreso,Foto,Resumen) VALUES(?,?,?,?,?)");
        $sNombre = utf8_encode ($_POST['tNombre']);
        $sSalario = $_POST['tSalario'];
        $sIngreso = $_POST['tIngreso'];
        $BytesFoto = NULL;
        $BytesResumen = NULL;

        $Enunciado->bind_param('sisbb',$sNombre,$sSalario,$sIngreso,$BytesFoto,$BytesResumen);
        if (is_uploaded_file($_FILES['fFoto']['tmp_name'])){
          $fiFoto = fopen($_FILES['fFoto']['tmp_name'], "rb");
          if ($fiFoto!=false){
            while (!feof($fiFoto)){
              $Enunciado->send_long_data(3, fread($fiFoto, 8192));
            }
            fclose($fiFoto);
          }
        } else {
          printf("Error Upload File: (%d) %s",$HTTP_POST_FILES['fFoto']['error'],$Enlace->error);
          exit();
        }

        if (is_uploaded_file($_FILES['fResumen']['tmp_name'])){
          $fiResumen = fopen($_FILES['fResumen']['tmp_name'], "rb");
          if ($fiResumen!=false){
            while (!feof($fiResumen)){
              $Enunciado->send_long_data(4, fread($fiResumen, 8192));
            }
            fclose($fiResumen);
          }
        } else {
          printf("Error Upload File: (%d) %s",$HTTP_POST_FILES['fResumen']['error'],$Enlace->error);
          exit();
        }

        if ($Enunciado->execute()) {
          print("Inserción Exitosa!<br/>");
        }else {
          printf("Error: (%d) %s",$Enlace->errno,$Enlace->error);
          exit();
        }
        $Enunciado->close();
        $Enlace->close();
      }

Si el botón que se presionó fue bCargar, es porque se desea insertar un registro.
Dado que para la inserción de un archivo primero debemos pasar por una serie de funciones, usamos el método prepare para realizar una inserción con formato.
Inicializamos las variables a utilizar y luego hacemos una correspondencia entre ellas y los valores para la sentencia de MySQL con el método bind_param.
Luego hacemos las lecturas con la función is_uploaded_file de los archivos de Imagen y de Texto y asignándolos a su variable respectiva.
Con todas las variables y sus valores respectivos asignados, ejecutamos el enunciado con el método Execute. Si no hay ningún error, la inserción se habrá realizado exitosamente.

Script JSP (Personal.jsp)

        if((String)Parameters.get("bCargar")!=null){
          try{
            PE = Conexion.prepareStatement("INSERT INTO Registros (Nombre,Salario,Ingreso,Foto,Resumen) VALUES(?,?,?,?,?)");
            String sNombre = (String)Parameters.get("tNombre");
            String sSalario = (String)Parameters.get("tSalario");
            String sIngreso = (String)Parameters.get("tIngreso");
            InputStream isFoto = (InputStream)Parameters.get("fFoto");
            String sResumen = (String)Parameters.get("fResumen");
            PE.setString(1,sNombre);
            PE.setInt(2,Integer.parseInt(sSalario));
            PE.setString(3,sIngreso);
            PE.setBinaryStream(4,isFoto);
            PE.setString(5,sResumen);
            PE.executeUpdate();
            out.println("Inserción Exitosa!<br/>");
          }
          catch (SQLException e) { out.println(e.toString()); }
          catch (Exception e) { out.println(e.toString()); }
          finally {
            PE.close();
            Conexion.close();
          }
        }

Para el caso de JSP el caso es más simple aunque el principio es el mismo; tomando el valor respectivo del Hashtable Parameters. La inserción con formato se hace con el método prepareStatement. Se puede notar que la lectura del archivo puede llevarse de inmediato a la variable correspondiente según la misma con setString, setInt, setBinaryStream. Finalmente realizamos la inserción con el método executeUpdate

Script JSP (Personal.jsp)
Seguimos ahora con la extracción de los registros que están en la base de datos:

        if((String)Parameters.get("bListar")!=null){
          String FS = System.getProperty("file.separator");//Separador de Archivo o de Directorio
          //Buscar ruta del Script
          String ScriptRoot = application.getRealPath("");
          ScriptRoot = ScriptRoot.replace("\\",FS);//Reemplaza \ por FS
          ScriptRoot = ScriptRoot.replace("/",FS);//Reemplaza / por FS
          String FileName = "JSP.Personal.RTF";
          String FullFileName = ScriptRoot+FS+"Files"+FS+FileName;
          String ImageJPG = ScriptRoot+FS+"joseluisbz.jpg";
          String ImagePNG = ScriptRoot+FS+"Empresa.png";
          try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(FullFileName));
            bw.write(sHeader);
            int[] iFormato = new int[1];
            int[] iAlto = new int[1];
            int[] iAncho = new int[1];
            String sBytesJPG = ByteFileImageString(ImageJPG,iFormato,iAlto,iAncho);
            if (sBytesJPG.equals("Error")){
              out.println("Error: el Archivo "+ImageJPG+" no es PNG o JPG");
              System.exit(0);
            }
            String InfImagenJPG = RTFImagen(sBytesJPG,iFormato[0],iAlto[0],iAncho[0],100,100,iAlto[0]*10,iAncho[0]*10,0,0,0,0);
            String sBytesPNG = ByteFileImageString(ImagePNG,iFormato,iAlto,iAncho);
            if (sBytesPNG.equals("Error")){
              out.println("Error: el Archivo "+ImagePNG+" no es PNG o JPG");
              System.exit(0);
            }
            String InfImagenPNG = RTFImagen(sBytesPNG,iFormato[0],iAlto[0],iAncho[0],100,100,iAlto[0]*10,iAncho[0]*10,0,0,0,0);
            String sBytesIMG;
            String InfImagenIMG;
            //sFrmtBS(/*Alineacion*/,/*Color Frontal*/,/*Color Fondo*/,/*Tipo Fuente*/,/*Tamaño Fuente*/);
            String FrmtTitle = sFrmtBS(1,1,2,5,20);
            String FrmtTexto = sFrmtBS(2,1,2,4,12);
            //sFrmtSP(/*Negrita*/,/*Italica*/,/*Subrayado*/);
            String FrmtEspec = sFrmtSP(1,0,0);
            String FrmtCampo = sFrmtSP(0,0,1);
            String FrmtValor = sFrmtSP(0,1,0);
            PE = Conexion.prepareStatement("SELECT * FROM Registros");
            Resultado = PE.executeQuery();
            Resultado.last();
            int NumRegistros = Resultado.getRow();Resultado.beforeFirst();
            while(Resultado.next()){
              //sTablIH(/*EspMd*/,/*Posic*/,/*Align*/,/*Borde*/,/*Grosor*/,/*Color*/)
              //sCeldaH(/*Ancho*/,/*Mezcla*/,/*AligV*/,/*Borde*/,/*Grosr*/,/*Color*/)
              bw.write(sTexto(FrmtTitle+FrmtEspec,"Empresa Limitada"));
              bw.write(sNParag);
              bw.write(sTablIH(10,10,1,1,10,2));//Inicio Cabecera de Tabla
              bw.write(sCeldaH(4000,0,0,2,10,2));
              bw.write(sCeldaH(8000,0,0,2,10,2));
              bw.write(sTablFH());//Fin Cabecera de Tabla
              bw.write(sCeldaC(sFrmtBS(1,0,0,0,0),InfImagenPNG));
              bw.write(sCeldaC(sFrmtBS(1,0,0,0,0),InfImagenJPG));
              bw.write(sTablFF());//Fin de Tabla
              bw.write(sNLinea+sNLinea);//2 Saltos de Línea
              bw.write(sTexto(FrmtCampo+FrmtTexto,"Nombre: "));
              bw.write(sTexto(FrmtValor+FrmtTexto,Resultado.getString(1)));
              bw.write(sNLinea);
              bw.write(sTexto(FrmtCampo+FrmtTexto,"Salario: "));
              bw.write(sTexto(FrmtValor+FrmtTexto,String.valueOf(Resultado.getInt(2))));
              bw.write(sNLinea);
              sBytesIMG = ByteStreamImageString(Resultado.getBytes(4),iFormato,iAlto,iAncho);
              InfImagenIMG = RTFImagen(sBytesIMG,iFormato[0],iAlto[0],iAncho[0],100,100,iAlto[0]*10,iAncho[0]*10,0,0,0,0);
              bw.write(InfImagenIMG);
              bw.write(sTexto(FrmtCampo+FrmtTexto,"Resumen: "));
              bw.write(sTexto(FrmtValor+FrmtTexto,Resultado.getString(5)));
              NumRegistros--;
              if (NumRegistros>0){
                bw.write(sNPagina);//Nueva Página
              }
            }
            bw.write(sFooter);
            bw.close();
            out.println("<a href=\"http://localhost/"+"Files"+"/"+FileName+"\">http://localhost/"+"Files"+"/"+FileName+"</a><P>");
          }
          catch (Exception e) { out.println(e.toString()); }
        }

Si se ha presionado el botón bListar, el usuario desea producir un archivo RTF con todos los registros que están en la base de datos.
Primero almacenamos en FS la manera en la que el sistema operativo delimita los directorios, subdirectorios y archivos; en Windows es con “\” en Linux es con “/”.
Luego determinamos la ruta de alojamiento del Script almacenándola en una variable llamada ScriptRoot, luego actualizamos la manera en que nuestro PHP o JSP presenta el delimitador de directorios y archivos a la manera del Sistema Operativo.
Se creará un archivo RTF llamado “JSP.Personal.RTF” y se almacenará en un subdirectorio llamado “Files” en la misma ruta donde se aloja este script.
ImageJPG y ImagePNG son archivos que se insertarán en el RTF.
FullFileName se crea el archivo RTF.
Las variables iFormato, iAlto, iAncho nos permiten pasar por referencia el formato, el alto y el ancho de la imagen que se insertará.
ByteFileImageString Obtiene los bytes del archivo imagen, el formato, el alto y el ancho.
RTFImagen es una cadena de texto que representa la imagen la imagen a insertar en el archivo con sus respectivos formatos.
FrmtTitle y FrmtTexto son los formatos básicos de nuestro archivo, uno para el título y el otro para el texto en general.
sFrmtSP, FrmtCampo y FrmtValor son formatos “especiales” que nos permiten hacer modificaciones adicionales a nuestro texto.
Preparamos la consulta con formato usando el método prepareStatement y la ejecutamos con executeQuery.
Almacenamos el resultado en la variable Resultado. Para no insertar una página en blanco al final necesitamos saber cuantos registros arrojó la consulta, para ello invocamos el método last, almacenamos el número de la fila en NumRegistros con getRow y posteriormente beforeFirst para poder llamar el método next.
Insertamos los campos y el valor de cada registro teniendo en cuenta el tipo de cada uno de ellos.
La inserción de texto, de conformación de tabla, celdas y su contenido se hacen a continuación, según lo descrito el Script de RTF.
Una vez finalizado publicamos el enlace con la que el usuario puede acceder al archivo RTF creado.

Script PHP (Personal.php)
La forma en que PHP crea el archivo RTF para extraer los registros y presentarlos es muy similar a la que los realiza JSP.

      if (isset($_POST['bListar'])){
        $FS = DIRECTORY_SEPARATOR;//Separador de Archivo o de Directorio
        //Buscar ruta del Script
        $ScriptRoot = getenv("DOCUMENT_ROOT");
        $ScriptRoot = str_replace("/",$FS,$ScriptRoot);//Reemplaza / por $FS
        $ScriptRoot = str_replace("\\",$FS,$ScriptRoot);//Reemplaza \ por $FS
        $FileName = "PHP.Personal.RTF";
        $FullFileName = $ScriptRoot.$FS."Files".$FS.$FileName;
        $ImageJPG = $ScriptRoot.$FS."joseluisbz.jpg";
        $ImagePNG = $ScriptRoot.$FS."Empresa.png";
        $fw = fopen($FullFileName, "wb");
        if($fw){
          fwrite($fw,$sHeader);
          $iFormato = NULL;
          $iAlto = NULL;
          $iAncho = NULL;
          $sBytesJPG = ByteFileImageString($ImageJPG,$iFormato,$iAlto,$iAncho);
          if (strcmp($sBytesJPG,"Error")==0){
            print("Error: el Archivo ".$ImageJPG." no es PNG o JPG");
            exit();
          }
          $InfImagenJPG = RTFImagen($sBytesJPG,$iFormato,$iAlto,$iAncho,100,100,$iAlto*10,$iAncho*10,0,0,0,0);
          $sBytesPNG = ByteFileImageString($ImagePNG,$iFormato,$iAlto,$iAncho);
          if (strcmp($sBytesPNG,"Error")==0){
            print("Error: el Archivo ".$ImagePNG." no es PNG o JPG");
            exit();
          }
          $InfImagenPNG = RTFImagen($sBytesPNG,$iFormato,$iAlto,$iAncho,100,100,$iAlto*10,$iAncho*10,0,0,0,0);
          $sBytesIMG = NULL;
          $InfImagenIMG = NULL;
          //sFrmtBS(/*Alineacion*/,/*Color Frontal*/,/*Color Fondo*/,/*Tipo Fuente*/,/*Tamaño Fuente*/);
          $FrmtTitle = sFrmtBS(1,1,2,5,20);
          $FrmtTexto = sFrmtBS(2,1,2,4,12);
          //sFrmtSP(/*Negrita*/,/*Italica*/,/*Subrayado*/);
          $FrmtEspec = sFrmtSP(1,0,0);
          $FrmtCampo = sFrmtSP(0,0,1);
          $FrmtValor = sFrmtSP(0,1,0);

          if ($Enunciado = $Enlace->prepare("SELECT * FROM Registros")) {
            $Enunciado->execute();
            $Enunciado->bind_result($sNombre,$sSalario,$sIngreso,$BytesFoto,$BytesResumen);
            $Enunciado->store_result();
            $NumRegistros = $Enunciado->num_rows;
            while ($Enunciado->fetch()) {
              //sTablIH(/*EspMd*/,/*Posic*/,/*Align*/,/*Borde*/,/*Grosor*/,/*Color*/)
              //sCeldaH(/*Ancho*/,/*Mezcla*/,/*AligV*/,/*Borde*/,/*Grosr*/,/*Color*/)
              fwrite($fw,sTexto($FrmtTitle.$FrmtEspec,"Empresa Limitada"));
              fwrite($fw,$sNParag);
              fwrite($fw,sTablIH(10,10,1,1,10,2));//Inicio Cabecera de Tabla
              fwrite($fw,sCeldaH(4000,0,0,2,10,2));
              fwrite($fw,sCeldaH(8000,0,0,2,10,2));
              fwrite($fw,sTablFH());//Fin Cabecera de Tabla
              fwrite($fw,sCeldaC(sFrmtBS(1,0,0,0,0),$InfImagenPNG));
              fwrite($fw,sCeldaC(sFrmtBS(1,0,0,0,0),$InfImagenJPG));
              fwrite($fw,sTablFF());//Fin de Tabla
              fwrite($fw,$sNLinea.$sNLinea);//2 Saltos de Línea
              fwrite($fw,sTexto($FrmtCampo.$FrmtTexto,"Nombre: "));
              fwrite($fw,sTexto($FrmtValor.$FrmtTexto,utf8_decode($sNombre)));
              fwrite($fw,$sNLinea);
              fwrite($fw,sTexto($FrmtCampo.$FrmtTexto,"Salario: "));
              fwrite($fw,sTexto($FrmtValor.$FrmtTexto,$sSalario));
              fwrite($fw,$sNLinea);
              $sBytesIMG = ByteStreamImageString($BytesFoto,$iFormato,$iAlto,$iAncho);
              $InfImagenIMG = RTFImagen($sBytesIMG,$iFormato,$iAlto,$iAncho,100,100,$iAlto*10,$iAncho*10,0,0,0,0);
              fwrite($fw,$InfImagenIMG);
              fwrite($fw,sTexto($FrmtCampo.$FrmtTexto,"Resumen: "));
              fwrite($fw,sTexto($FrmtValor.$FrmtTexto,$BytesResumen));
              $NumRegistros--;
              if($NumRegistros>0){
                fwrite($fw,$sNPagina);//Nueva Página
              }
            }
            $Enunciado->close();
          }
          fwrite($fw,$sFooter);
          fclose($fw);
            print("<a href=\"http://localhost/"."Files"."/".$FileName."\">http://localhost/"."Files"."/".$FileName."</a><P>");
        } else {
          print($FullFileName." (El sistema no puede encontrar la ruta especificada)");
          exit();
        }
      }

Con el método prepare se prepara la consulta, se realiza con el método execute y se asigna a la variable respectiva el valor de cada campo con el método bind_result; como necesitamos saber el número de registros obtenidos invocamos el método num_rows no sin antes invocar el método store_result para que el valor de las filas correspondiente a cada registra no sea cero.

      if (isset($_POST['bBorrar'])){
        $Consulta = "DELETE FROM Registros";
        $Resultado = $Enlace->query($Consulta);
        if (!$Resultado) {
          printf("Error: (%d) %s",$Enlace->errno,$Enlace->error);
          exit();
        }
        print("Eliminación Exitosa!<br/>");
      }
    ?>

Para la eliminación se determina si el botón presionado es bBorrar, luego se establece la consulta y se ejecuta almacenándose el resultado con el fin de derminar si fue exitoso o fallido, en ambos casos se desplegará un mensaje según su valor.

Script JSP (Personal.jsp)

        if((String)Parameters.get("bBorrar")!=null){
          try {
            Enunciado = Conexion.createStatement();
            Enunciado.executeUpdate("DELETE FROM Registros");
            out.println("Eliminación Exitosa!<br/>");
          }
          catch (SQLException e) { out.println(e.toString()); }
        }
      }
    %>

De igual forma se realiza la eliminación de los registros en JSP.
Con esto hemos finalizado nuestro tutorial.

Publicado en JSP, MySQL, PHP, RTF, Server, Servidores Web, Software | Etiquetado , , , , , , , , , , | 11 comentarios

Script de Funciones RTF para JSP y PHP


Script JSP (RTF.jsp)
Vamos a detallar someramente el Script correspondiente a RTF empezando por las importaciones.

<%@ page import="java.lang.*" %>
<%@ page import="java.io.*" %>
<%!

Header indicador de que es un srchivo RTF, con tipo de definición de idioma.

  String sRTF = "{\\rtf1"//Indicador RTF
          +"\\ansi\\ansicpg1252"//1252->Western European
          +"\\deff0\\deflang9226 \n";//9226->Español Colombia

Definiciones de cadenas para definir nuevo parágrafo, nueva página y nueva línea.

  String sNParag = "\\par ";//Nuevo Parágrafo
  String sNPagina = "\n\\page \\par \n";//Nueva Página
  String sNLinea = "\n\\line";//Nueva Línea

Definiciones de Fuentes. Aunque se puede configurar sin necesidad de establecer una enumeración, esto lo hice por comodidad e incluí un salto de línea “\n” en el archivo RTF generado, más no en su presentación.
Podemos establecer las fuentes que deseemos utilizar.

  String[] sFFam = {"\n",
          " {\\f1\\fnil\\fprq1\\fcharset0 TlwgMono;}\n",
          " {\\f2\\fswiss\\fprq1\\fcharset0 Arial;}\n",
          " {\\f3\\froman\\fprq1\\fcharset0 Times New Roman;}\n",
          " {\\f4\\fmodern\\fprq1\\fcharset0 Courier New;}\n",
          " {\\f5\\fscript\\fprq1\\fcharset0 Edwardian Script ITC;}\n"}; //Familia de Fuentes
  String sTablaF = "\n{\\fonttbl\n"+sFFam[0]+sFFam[1]
          +sFFam[2]+sFFam[3]+sFFam[4]+sFFam[5]+"}\n";//Tabla de Fuentes

De igual manera se define la tabla de colores que se utilizaría en nuestro RTF

  String[] sFCol = {
          " \\red0\\green0\\blue0;\n", //Negro
          " \\red0\\green0\\blue255;\n", //Azul
          " \\red0\\green255\\blue255;\n", //Cian
          " \\red0\\green255\\blue0;\n", //Verde
          " \\red255\\green0\\blue255;\n", //Magenta
          " \\red255\\green0\\blue0;\n", //Red
          " \\red255\\green255\\blue0;\n", //Amarillo
          " \\red255\\green255\\blue255;\n" //Blanco
           }; //Color de Fuentes
  String sTablaC = "\n{\\colortbl;\n"+sFCol[0]+sFCol[1]+sFCol[2]+sFCol[3]+
          sFCol[4]+sFCol[5]+sFCol[6]+sFCol[7]+"}\n";//Tabla de Colores

Por último definimos el Header en su totalidad de nuestro RTF y el Footer (fin de RTF)

  String sHeader = sRTF+sTablaF+sTablaC;
  String sFooter = "}";

Script PHP (RTF.php)
La contraparte de PHP del código anterior:

<?php

  $sRTF = "{\\rtf1"//Indicador RTF
          ."\\ansi\\ansicpg1252"//1252->Western European
          ."\\deff0\\deflang9226 \n";//9226->Español Colombia

  $sNParag = "\\par ";//Nuevo Parágrafo
  $sNPagina = "\n\\page \\par \n";//Nueva Página
  $sNLinea = "\n\\line";//Nueva Línea

  $sFFam = array("\n",
          " {\\f1\\fnil\\fprq1\\fcharset0 TlwgMono;}\n",
          " {\\f2\\fswiss\\fprq1\\fcharset0 Arial;}\n",
          " {\\f3\\froman\\fprq1\\fcharset0 Times New Roman;}\n",
          " {\\f4\\fmodern\\fprq1\\fcharset0 Courier New;}\n",
          " {\\f5\\fscript\\fprq1\\fcharset0 Edwardian Script ITC;}\n"); //Familia de Fuentes
  $sTablaF = "\n{\\fonttbl\n".$sFFam[0].$sFFam[1]
          .$sFFam[2].$sFFam[3].$sFFam[4].$sFFam[5]."}\n";//Tabla de Fuentes

  $sFCol = array(
          " \\red0\\green0\\blue0;\n", //Negro
          " \\red0\\green0\\blue255;\n", //Azul
          " \\red0\\green255\\blue255;\n", //Cian
          " \\red0\\green255\\blue0;\n", //Verde
          " \\red255\\green0\\blue255;\n", //Magenta
          " \\red255\\green0\\blue0;\n", //Red
          " \\red255\\green255\\blue0;\n", //Amarillo
          " \\red255\\green255\\blue255;\n" //Blanco
           ); //Color de Fuentes
  $sTablaC = "\n{\\colortbl;\n".$sFCol[0].$sFCol[1].$sFCol[2].$sFCol[3].
          $sFCol[4].$sFCol[5].$sFCol[6].$sFCol[7]."}\n";//Tabla de Colores

  $sHeader = $sRTF.$sTablaF.$sTablaC;
  $sFooter = "}";

Ahora definiremos algunos formatos básicos y necesarios para la presentación de Texto y de Texto en Celdas de Tabla.
Primero los bordes de Tabla y/o de Celda.

  $aBorde = array(
    '\\brdrnone', //No border.
    '\\brdrs', //Single-thickness border.
    '\\brdrth', //Double-thickness border.
    '\\brdrsh', //Shadowed border.
    '\\brdrdb', //Double border.
    '\\brdrdot', // Dotted border.
    '\\brdrdash', //Dashed border.
    '\\brdrinset', //Inset border.
    '\\brdroutset'  //Outset border.
  );//Arreglo de Tipos de Borde

Alineación de texto

  $aAlign = array(
    "",//  Dejar Igual
    "\\qc",//  Centrar
    "\\ql",//  Izquierda
    "\\qr",//  Derecha
    "\\qj",//  Justificar
    "\\qd" //  Distribuir
  );//Tipo De Alineación Horizontal de Texto

Alineación Horizontal de Tabla

  $aAliHT = array(
    '\\trqc', //Centers a table row with respect to its containing column.
    '\\trql', //Left-justifies a table row with respect to its containing column.
    '\\trqr'  //Right-justifies a table row with respect to its containing column.
  );//Tipo De Alineación Horizontal de Tabla

Alineación Vertical de texto en celda

  $aAliVC = array(
    "\\clvertalt", //Text is top-aligned in cell (the default).
    "\\clvertalc", //Text is centered vertically in cell.
    "\\clvertalb"  //Text is bottom-aligned in cell.
  );//Tipo De Alineación Vertical de Celda

Mezcla de celdas verticalmente en una tabla

  $aUneVC = array(
    "", //Ninguna Mezcla.
    "\\clvmgf", //The first cell in a range of table cells to be vertically merged
    "\\clvmrg"  //Contents of the table cell are vertically merged with those of the preceding cell
  );//Tipo De Unión Vertical de Celda

Script JSP (RTF.jsp)
Ya se detalló con anterioridad unas definiones que se utilizarán en las diferentes funciones o métodos del Archivo RTF.jsp o RTF.php.

  String[] aBorde = {
    "\\brdrnone", //No border.
    "\\brdrs", //Single-thickness border.
    "\\brdrth", //Double-thickness border.
    "\\brdrsh", //Shadowed border.
    "\\brdrdb", //Double border.
    "\\brdrdot", // Dotted border.
    "\\brdrdash", //Dashed border.
    "\\brdrinset", //Inset border.
    "\\brdroutset"  //Outset border.
  };//Arreglo de Tipos de Borde

  String[] aAlign = {
    "",//  Dejar Igual
    "\\qc",//  Centrar
    "\\ql",//  Izquierda
    "\\qr",//  Derecha
    "\\qj",//  Justificar
    "\\qd" //  Distribuir
  };//Tipo De Alineación Horizontal de Texto

  String[] aAliHT = {
    "\\trqc", //Centers a table row with respect to its containing column.
    "\\trql", //Left-justifies a table row with respect to its containing column.
    "\\trqr"  //Right-justifies a table row with respect to its containing column.
  };//Tipo De Alineación Horizontal de Tabla

  String[] aAliVC = {
    "\\clvertalt", //Text is top-aligned in cell (the default).
    "\\clvertalc", //Text is centered vertically in cell.
    "\\clvertalb"  //Text is bottom-aligned in cell.
  };//Tipo De Alineación Vertical de Celda

  String[] aUneVC = {
    "", //Ninguna Mezcla.
    "\\clvmgf", //The first cell in a range of table cells to be vertically merged
    "\\clvmrg"  //Contents of the table cell are vertically merged with those of the preceding cell
  };//Tipo De Unión Vertical de Celda

Ahora detallamos unas funciones que nos permiten la creación de tablas y celdas.

  String sTablIH(int EspMd, int Posic, int AligH, int Borde,int Grosr,int Color) {
    //Inicio de Cabecera de Tabla;
    //\trowd  Sets table row defaults.
    //\trgaphN Half the space between the cells of a table row in twips.
    String sEspMd = "\\trgaph"+String.valueOf(EspMd);//Espacio medio en twips entre celdas de una fila
    //\trleftN Position in twips of the leftmost edge of the table with respect to the left edge of its column.
    String sPosic = "\\trleft"+String.valueOf(Posic);//
    //\trhdr  Table row header. This row should appear at the top of every page on which the current table appears.
    String sHdT = "\n\\ltrrow\\trowd"+sEspMd+sPosic+aAliHT[AligH];//Cabecera de la Tabla
    //TipoDeBorde
    String sBorde = Borde==0?"":aBorde[Borde];//Tipo de Borde
    sHdT = Borde==0?sHdT+" \n":sHdT+"\\trhdr \n";
    //GrosorDeBorde
    String sGrosr = Grosr==0?"":"\\brdrw"+String.valueOf(Grosr);//Grosor en twips del borde, debe ser <= 255.
    //ColorDeBorde
    String sColor = Color==0?"":"\\brdrcf"+String.valueOf(Color);//Color del borde, según tabla de colores.
    //BordesDeTabla
    String sTop = "\\trbrdrt"+sBorde+sGrosr+sColor+" ";//Table row border top
    String sBot = "\\trbrdrb"+sBorde+sGrosr+sColor+" ";//Table row border bottom
    String sLft = "\\trbrdrl"+sBorde+sGrosr+sColor+" ";//Table row border left
    String sRgt = "\\trbrdrr"+sBorde+sGrosr+sColor+" ";//Table row border right
    String sHHz = "\\trbrdrh"+sBorde+sGrosr+sColor+" ";//Table row border horizontal (inside).
    String sHVt = "\\trbrdrv"+sBorde+sGrosr+sColor+" ";//Table row border vertical (inside).
    String sTablIH = sHdT+sTop+sLft+sBot+sRgt+"\n"+sHHz+sHVt+"\n";
    return sTablIH;
  }

  String sTablFH() {
    //Fin de Cabecera de Tabla;
    String sTablFH = "\n\\pard\\intbl\\pard\\plain \n";
    //String sTablFH = "\n\\pard\\intbl\\pard\\plain \n";
    return sTablFH;
  }

  String sTablIF(int EspMd, int Posic, int AligH) {
    //Inicio de Fila de Tabla;
    //\trowd  Sets table row defaults.
    //\trgaphN Half the space between the cells of a table row in twips.
    String sEspMd = "\\trgaph"+String.valueOf(EspMd);//Espacio medio en twips entre celdas de una fila
    //\trleftN Position in twips of the leftmost edge of the table with respect to the left edge of its column.
    String sPosic = "\\trleft"+String.valueOf(Posic);//
    String sTablIF = "\n\\row\\pard\n\\trowd"+sEspMd+sPosic+aAliHT[AligH]+" \n";//Fila de la Tabla
    return sTablIF;
  }

  String sTablFF() {
    //Fin de Fila de Tabla;
    String sTablFF = "\n\\row\\pard \n";
    return sTablFF;
  }

  String sCeldaH(int Ancho, int Mezcla, int AligV, int Borde,int Grosr,int Color) {
    //\[MezclaVertical]\[AlineacionVertical]\TipoDeBorde\GrosorDeBorde\ColorDeBorde
    //TipoDeBorde
    String sBorde = Borde==0?"":aBorde[Borde];//Tipo de Borde
    //GrosorDeBorde
    String sGrosr = Grosr==0?"":"\\brdrw"+String.valueOf(Grosr);//Grosor en twips del borde, debe ser <= 255.
    //ColorDeBorde
    String sColor = Color==0?"":"\\brdrcf"+String.valueOf(Color);//Color del borde, según tabla de colores.
    //BordesDeCelda
    String sTop = "\\clbrdrt"+sBorde+sGrosr+sColor+" ";//Top table cell border
    String sBot = "\\clbrdrb"+sBorde+sGrosr+sColor+" ";//Bottom table cell border
    String sLft = "\\clbrdrl"+sBorde+sGrosr+sColor+" ";//Left row border left
    String sRgt = "\\clbrdrr"+sBorde+sGrosr+sColor+" ";//Right table cell border
    //\cellxN	Defines the right boundary of a table cell, including its half of the space between cells.
    String sLimit = "\\cellx"+Ancho+" \n";
    String sCeldaH = aUneVC[Mezcla]+aAliVC[AligV]+sTop+sLft+sBot+sRgt+sLimit;
    return sCeldaH;
  }

sTablIH nos permite definir el inicio de la cabecera de la tabla, con sus formatos. El código como tal está documentado.
sTablFH indica el fin de la cabecera de la tabla.
sTablIF indica inicio de definición de fila.
sTablFF indica fin de definición de fila.
sCeldaH permite establecer la definición de celda, formato de bordes, etc.

Script PHP (RTF.php)
De igual forma se definieron las funciones para PHP. Se debe tener en cuenta que las enumeraciones en cada función donde se necesitan se deben declarar como global.

  function sTablIH($EspMd,$Posic,$AligH,$Borde,$Grosr,$Color) {
    //Inicio de Cabecera de Tabla;
    //\trowd  Sets table row defaults.
    //\trgaphN Half the space between the cells of a table row in twips.
    $sEspMd = "\\trgaph".$EspMd;//Espacio medio en twips entre celdas de una fila
    //\trleftN Position in twips of the leftmost edge of the table with respect to the left edge of its column.
    $sPosic = "\\trleft".$Posic;//
    //\trhdr  Table row header. This row should appear at the top of every page on which the current table appears.
    global $aAliHT;
    $sHdT = "\n\\ltrrow\\trowd".$sEspMd.$sPosic.$aAliHT[$AligH];//Cabecera de la Tabla
    //TipoDeBorde
    global $aBorde;
    $sBorde = ($Borde==0)?"":$aBorde[$Borde];//Tipo de Borde
    $sHdT = ($Borde==0)?$sHdT." \n":$sHdT."\\trhdr \n";
    //GrosorDeBorde
    $sGrosr = ($Grosr==0)?"":"\\brdrw".$Grosr;//Grosor en twips del borde, debe ser <= 255.
    //ColorDeBorde
    $sColor = ($Color==0)?"":"\\brdrcf".$Color;//Color del borde, según tabla de colores.
    //BordesDeTabla
    $sTop = "\\trbrdrt".$sBorde.$sGrosr.$sColor." ";//Table row border top
    $sBot = "\\trbrdrb".$sBorde.$sGrosr.$sColor." ";//Table row border bottom
    $sLft = "\\trbrdrl".$sBorde.$sGrosr.$sColor." ";//Table row border left
    $sRgt = "\\trbrdrr".$sBorde.$sGrosr.$sColor." ";//Table row border right
    $sHHz = "\\trbrdrh".$sBorde.$sGrosr.$sColor." ";//Table row border horizontal (inside).
    $sHVt = "\\trbrdrv".$sBorde.$sGrosr.$sColor." ";//Table row border vertical (inside).
    $sTablIH = $sHdT.$sTop.$sLft.$sBot.$sRgt."\n".$sHHz.$sHVt."\n";
    return $sTablIH;
  }

  function sTablFH() {
    //Fin de Cabecera de Tabla;
    $sTablFH = "\n\\pard\\intbl\\pard\\plain \n";
    return $sTablFH;
  }

  function sTablIF($EspMd,$Posic,$AligH) {
    //Inicio de Fila de Tabla;
    //\trowd  Sets table row defaults.
    //\trgaphN Half the space between the cells of a table row in twips.
    $sEspMd = "\\trgaph".$EspMd;//Espacio medio en twips entre celdas de una fila
    //\trleftN Position in twips of the leftmost edge of the table with respect to the left edge of its column.
    $sPosic = "\\trleft".$Posic;//
    global $aAliHT;
    $sTablIF = "\n\\row\\pard\n\\trowd".$sEspMd.$sPosic.$aAliHT[$AligH]." \n";//Fila de la Tabla
    return $sTablIF;
  }

  function sTablFF() {
    //Fin de Fila de Tabla;
    $sTablFF = "\n\\row\\pard \n";
    return $sTablFF;
  }

  function sCeldaH($Ancho,$Mezcla,$AligV,$Borde,$Grosr,$Color) {
    //\[MezclaVertical]\[AlineacionVertical]\TipoDeBorde\GrosorDeBorde\ColorDeBorde
    //TipoDeBorde
    global $aBorde;
    $sBorde = ($Borde==0)?"":$aBorde[$Borde];//Tipo de Borde
    //GrosorDeBorde
    $sGrosr = ($Grosr==0)?"":"\\brdrw".$Grosr;//Grosor en twips del borde, debe ser <= 255.
    //ColorDeBorde
    $sColor = ($Color==0)?"":"\\brdrcf".$Color;//Color del borde, según tabla de colores.
    //BordesDeCelda
    $sTop = "\\clbrdrt".$sBorde.$sGrosr.$sColor." ";//Top table cell border
    $sBot = "\\clbrdrb".$sBorde.$sGrosr.$sColor." ";//Bottom table cell border
    $sLft = "\\clbrdrl".$sBorde.$sGrosr.$sColor." ";//Left row border left
    $sRgt = "\\clbrdrr".$sBorde.$sGrosr.$sColor." ";//Right table cell border
    //\cellxN	Defines the right boundary of a table cell, including its half of the space between cells.
    $sLimit = "\\cellx".$Ancho." \n";
    global $aUneVC;
    global $aAliVC;
    $sCeldaH = $aUneVC[$Mezcla].$aAliVC[$AligV].$sTop.$sLft.$sBot.$sRgt.$sLimit;
    return $sCeldaH;
  }

Ahora describimos unas funciones que son importantes para el manejo de texto.

  function sFrmtBS($Align,$CFrnt,$CFond,$Fuente,$Talla){
    //Formatos Necesarios
    $sCFrnt = "\\cf".$CFrnt;
    $sCFond = "\\cb".$CFond;
    $sFuente = "\\f".$Fuente;
    $sTalla = "\\fs".(2*$Talla);
    global $aAlign;
    $sFrmtBS = $aAlign[$Align].$sCFrnt.$sCFond.$sFuente.$sTalla."\n";
    return $sFrmtBS;
  }

  function sFrmtSP($Negrt,$Italc,$Sbryd){
    //Aplicar o Quitar Formatos Especiales
    $sNegrt = ($Negrt==0)?"\\b0":"\\b";//  Negrita
    $sItalc = ($Italc==0)?"\\i0":"\\i";//  Itálica
    $sSbryd = ($Sbryd==0)?"\\ul0":"\\ul";// Subrayar
    $sFrmtSP = $sNegrt.$sItalc.$sSbryd."\n";
    return $sFrmtSP;
  }

  function sCeldaC($Formato, $Contenido) {
    $sCeldaC = "\\pard\\plain\\intbl\\ltrpar";
    //\cell	Denotes the end of a table cell.
    $sCeldaC = $sCeldaC.$Formato.$Contenido."\\cell \n";
    return $sCeldaC;
  }

  function sTexto($Formato,$Contenido) {
    $sTexto = $Formato.$Contenido."\n";
    return $sTexto;
  }

  function RTFImagen($ImageString,$Tipo,$Alto,$Ancho,$SclY,$SclX,
          $AltP,$AncP,$CropL,$CropR,$CropT,$CropB){
    $RTFImagen = "\n"."{\\pict";
    $sLibI = "\\";
   switch ($Tipo){
    case 1:
      $sLibI = $sLibI."pngblip";
      break;
    case 2:
      $sLibI = $sLibI."jpegblip";
      break;
    }
    $sAlto = "\\pich".$Alto;
    $sAnch = "\\picw".$Ancho;
    $sSclX = "\\picscalex".$SclY;
    $sSclY = "\\picscaley".$SclX;
    $sAltP = "\\pichgoal".$AltP;
    $sAncP = "\\picwgoal".$AncP;
    $sCrpL = "\\piccropl".$CropL;
    $sCrpR = "\\piccropr".$CropR;
    $sCrpT = "\\piccropt".$CropT;
    $sCrpB = "\\piccropb".$CropB;
    $RTFImagen = $RTFImagen.$sSclX.$sSclY.$sCrpL.$sCrpR.$sCrpT.$sCrpB."\n".$sAnch.
            $sAlto.$sAncP.$sAltP.$sLibI."\n".$ImageString."\n}\\par";
    return $RTFImagen;
  }

sFrmtBS Permite establecer el formato básico necesario para la presentación de texto.
sFrmtSP Aparte del formato básico necesario, permite cambiar agregando o quitando otro formato opcional.
sCeldaC Permite desplegar el contenido de una celda en una tabla, teniendo en cuenta el formato.
sTexto Permite desplegar un texto requiriéndose su formato respectivo.
RTFImagen Permite incluir una imagen, recibiéndose como parámetros el formato de su presentación.

Script JSP (RTF.jsp)
El código para JSP es muy similar por no decir que es igual.

  String sFrmtBS(int Align, int CFrnt, int CFond, int Fuente, int Talla){
    //Formatos Necesarios
    String sCFrnt = "\\cf"+String.valueOf(CFrnt);
    String sCFond = "\\cb"+String.valueOf(CFond);
    String sFuente = "\\f"+String.valueOf(Fuente);
    String sTalla = "\\fs"+String.valueOf(2*Talla);
    String sFrmtBS = aAlign[Align]+sCFrnt+sCFond+sFuente+sTalla+"\n";
    return sFrmtBS;
  }

  String sFrmtSP(int Negrt, int Italc, int Sbryd){
    //Aplicar o Quitar Formatos Especiales
    String sNegrt = Negrt==0?"\\b0":"\\b";//  Negrita
    String sItalc = Italc==0?"\\i0":"\\i";//  Itálica
    String sSbryd = Sbryd==0?"\\ul0":"\\ul";// Subrayar
    String sFrmtSP = sNegrt+sItalc+sSbryd+"\n";
    return sFrmtSP;
  }

  String sCeldaC(String Formato, String Contenido) {
    String sCeldaC = "\\pard\\plain\\intbl\\ltrpar";
    //\cell	Denotes the end of a table cell.
    sCeldaC = sCeldaC+Formato+Contenido+"\\cell \n";
    return sCeldaC;
  }

  String sTexto(String Formato, String Contenido) {
    String sTexto = Formato+Contenido+"\n";
    return sTexto;
  }

  String RTFImagen(String ImageString,int Tipo,int Alto,int Ancho,int SclY,int SclX,
          int AltP,int AncP,int CropL,int CropR,int CropT,int CropB){
    String RTFImagen = "\n"+"{\\pict";
    String sLibI = "\\";
   switch (Tipo){
    case 1:
      sLibI = sLibI+"pngblip";
      break;
    case 2:
      sLibI = sLibI+"jpegblip";
      break;
    }
    String sAlto = "\\pich"+String.valueOf(Alto);
    String sAnch = "\\picw"+String.valueOf(Ancho);
    String sSclX = "\\picscalex"+String.valueOf(SclY);
    String sSclY = "\\picscaley"+String.valueOf(SclX);
    String sAltP = "\\pichgoal"+String.valueOf(AltP);
    String sAncP = "\\picwgoal"+String.valueOf(AncP);
    String sCrpL = "\\piccropl"+String.valueOf(CropL);
    String sCrpR = "\\piccropr"+String.valueOf(CropR);
    String sCrpT = "\\piccropt"+String.valueOf(CropT);
    String sCrpB = "\\piccropb"+String.valueOf(CropB);
    RTFImagen = RTFImagen+sSclX+sSclY+sCrpL+sCrpR+sCrpT+sCrpB+"\n"+sAnch+
            sAlto+sAncP+sAltP+sLibI+"\n"+ImageString+"\n}\\par";
    return RTFImagen;
  }

Ahora describiremos unas funciones que nos permiten acceder a la información de la imagen y disponer de ella para poder insertarla a algún archivo de formato RTF.

  String ByteFileImageString(String NombreImagen,int[] Formato,int[] Alto,int[] Ancho) {
    byte[] BytesFile = new byte[(int)(new File(NombreImagen).length())];
    FileInputStream fis;
    try {
      fis = new FileInputStream(NombreImagen);
      fis.read(BytesFile);
      fis.close();
    }
    catch (FileNotFoundException fnfe)
    {System.out.println(fnfe.toString());}
    catch (EOFException eofe)
    {System.out.println(eofe.toString());}
    catch (IOException ioe)
    {System.out.println(ioe.toString());}
    String ImageString = ByteStreamImageString(BytesFile,Formato,Alto,Ancho);
    return ImageString;
  }

  String ByteStreamImageString(byte[] ByteStream,int[] Formato,int[] Alto,int[] Ancho) {
    Alto[0] = 0;
    Ancho[0] = 0;
    Formato[0] = -1;
    String ImageString = "Error";
    if ((int)(ByteStream[0]&0xFF)==137 && (int)(ByteStream[1]&0xFF)==80 &&(int)(ByteStream[2]&0xFF)==78){
      Formato[0] = 1; //PNG
      Alto[0] = Byte2PosInt(ByteStream[22],ByteStream[23]);
      Ancho[0] = Byte2PosInt(ByteStream[18],ByteStream[19]);
    }
    if ((int)(ByteStream[0]&0xFF)==255 && (int)(ByteStream[1]&0xFF)==216
        &&(int)(ByteStream[2]&0xFF)==255 && (int)(ByteStream[3]&0xFF)==224){
      Formato[0] = 2; //JPG
      int PosJPG = 2;
      while (PosJPG<ByteStream.length){
        if (String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]).equals("FFC0")){
          Alto[0] = Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
          Ancho[0] = Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
        }
        PosJPG = PosJPG + 2 +Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
      }
    }
    if (Formato[0] > 0){
      ImageString = "";
      int Salto = 0;
      for (int i=0;i < ByteStream.length; i++){
        Salto++;
        ImageString = ImageString + String.format("%02x", ByteStream[i]);
        if (Salto==64){
          ImageString = ImageString + "\n";
          Salto = 0;
        }
      }
    }
    return ImageString;
  }

  private Integer Byte2PosInt(byte Byte08, byte Byte00) {
    return new Integer (((Byte08 & 0xFF) << 8)|((Byte00 & 0xFF) << 0));
  }
%>

ByteFileImageString Lee un archivo cualquiera en forma binaria, retorna su contenido convertido de Byte a su representación numérica, además si es un formato de imagen retorna su alto y Ancho.
ByteStreamImageString Recibe el contenido de representación numérica de cada Byte, determina si ese contenido corresponde a algún formato válido JPG o PNG, determina además el Alto y ancho.
Byte2PosInt Convierte dos Bytes, según el orden a su valor correspondiente a Entero.

Script PHP (RTF.php)
Finalizamos con el código en PHP de las funciones antes descritas.

  function ByteFileImageString($NombreImagen,&$Formato,&$Alto,&$Ancho) {
    $fis = fopen($NombreImagen, "rb");
    if ($fis!=false){
      $BytesFile = NULL;
      while (!feof($fis)){
        $BytesFile .= fread($fis, 8192);
      }
      fclose($fis);
    }else {
      printf("Error: ".$NombreImagen);
      exit();
    }
    $ImageString = ByteStreamImageString($BytesFile,$Formato,$Alto,$Ancho);
    return $ImageString;
  }

  function ByteStreamImageString($ByteStream,&$Formato,&$Alto,&$Ancho) {
    $Alto = 0;
    $Ancho = 0;
    $Formato = -1;
    $ImageString = "Error";
    if (ord($ByteStream[0])==137 && ord($ByteStream[1])==80 && ord($ByteStream[2])==78){
      $Formato = 1; //PNG
      $Alto = Byte2PosInt($ByteStream[22],$ByteStream[23]);
      $Ancho = Byte2PosInt($ByteStream[18],$ByteStream[19]);
    }
    if (ord($ByteStream[0])==255 && ord($ByteStream[1])==216
        && ord($ByteStream[2])==255 && ord($ByteStream[3])==224){
      $Formato = 2; //JPG
      $PosJPG = 2;
      while ($PosJPG<strlen($ByteStream)){
        if (sprintf("%02X%02X", ord($ByteStream[$PosJPG+0]),ord($ByteStream[$PosJPG+1]))=="FFC0"){
          $Alto = Byte2PosInt($ByteStream[$PosJPG+5],$ByteStream[$PosJPG+6]);
          $Ancho = Byte2PosInt($ByteStream[$PosJPG+7],$ByteStream[$PosJPG+8]);
        }
        $PosJPG = $PosJPG + 2 +Byte2PosInt($ByteStream[$PosJPG+2],$ByteStream[$PosJPG+3]);
      }
    }
    if ($Formato > 0){
      $ImageString = "";
      $Salto = 0;
      for ($i=0;$i < strlen($ByteStream); $i++){
        $Salto++;
        $ImageString = $ImageString.sprintf("%02x", ord($ByteStream[$i]));
        if ($Salto==64){
          $ImageString = $ImageString."\n";
          $Salto = 0;
        }
      }
    }
    return $ImageString;
  }

  function Byte2PosInt($Byte08,$Byte00) {
    return ((ord($Byte08) & 0xFF) << 8)|((ord($Byte00) & 0xFF) << 0);
  }
?>
Publicado en Funciones, Functions, Image, Java, JSP, PHP, Programación, Programming, RTF | Etiquetado , , , , , , , , | Deja un comentario

Httpd, PHP, Tomcat, Mod_JK, Java y MySQL en Windows y NetBeans (III)


Ahora voy a trabajar con las instalaciones de Java y NetBeans, con relación a las instalaciones anteriores.
En primer lugar tenía instalado el JDK Java 6 Update 17 y lo desinstalé, ahora mostraré como instalar una nueva versión de Java.

Descargué la versión Java SE Development Kit 6 Update 22 for Windows… procedemos con la instalación que inicia con la bienvenida a la cual le presionamos el botón “Next”. Establecemos el folder y las características de instalación y presionamos el botón “Next” Comienza el proceso de instalación Como también había desinstalado el JRE, debo seleccionar el folder para el JRE y presionamos el botón “Next” Empieza el proceso de instalación del JRE… Como es una actualización de Java tanto del JDK como del JRE el asistente solicitará reiniciar para aplicar los cambios Luego de esto el proceso finalizará, presionando el botón “Finish”

De las instalaciones anteriores, Apache Tomcat necesita de Java, pero como ahora hemos modificado su instalación, el Servicio se ha debido afectar, en mi caso me salió el siguiente error:
Windows no pudo iniciar el servicio Apache Tomcat6 en Equipo local.
Error 1067: El proceso ha terminado de forma inesperada.

o en inglés:
Could not start the Apache Tomcat6 service on Local Computer.
Error 1067: The process terminated unexpectedly.

Pueda que el mensaje de error sea de otro tipo:
Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
At least one of these environment variable is needed to run this program

En tal caso debemos indicarle a Tomcat donde encontrar al JDK o al JRE con:
SET JAVA_HOME = C:\Program Files\Java\jdk1.6.0_22\
SET JRE_HOME = C:\Program Files\Java\jre1.6.0_22\

Otra manera en la que se manifiesta este error en el caso de Tomcat 7 al actualizar la versión a Java 7 también es esta:
Windows no pudo iniciar Apache Tomcat 7.0 Tomcat7 en Equipo local.

Arrancamos CMD en modo administrador como se muestra…

Escribiendo “CMD” en el cuadro de texto ejecutar y cuando aparezca el ícono cmd.exe le damos click secundario (o click derecho), damos click primario (o click izquierdo) sobre la opción “Ejecutar como administrador“.

Iniciamos el Monitor de Tomcat 7 ingresando al subdirectorio \bin en su ruta de instalación la instrucción: tomcat7w.exe //MS/Tomcat7

Al iniciar el Monitor de Tomcat con click secundario elegimos la opción configurar

Vemos que está apuntando a la dirección del archivo de Java “jvm.dll” de la versión anterior, en este caso Java 6.

Cambiamos la ruta a la nueva disposición del archivo “jvm.dll” de Java 7 quedando así:

Ahora podemos iniciar Tomcat 7 sin ningún problema relacionado con este inconveniente.

Podemos ver que ha iniciado puesto que se ha corregido el problema.

También se puede dar el siguiente error:
Error occurred during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object

Esto se debe a que no se encuentra un archivo llamado rt.jar.  Entonces búsquelo dentro de JAVA_HOME\lib y copielo en JRE_HOME\lib
Con estos ajustes los problemas ocasionados a Apache Tomcat han debido solucionarse…

Puede darse el caso que no se arranque un servicio asociado a Tomcat debido a los privilegios de administrador que debe tener y se presenta este mensaje:

Para Tomcat 7 que es el servicio que debe iniciar cuando lo haga Windows y no tenga inconvenientes, vamos a la carpeta de instalación de Tomcat dentro del subdirectorio \bin.

Damos click secundario sobre el archivo tomcat7w.exe y aparecerá las propiedades del mismo…

Marcamos “Ejecutar este programa como administrador” y presionamos el botón “Aplicar”.

Luego presionamos el botón “cambiar la configuración para todos los usuarios”

En la pestaña “compatibilidad para todos los usuarios” también marcamos la casilla de verificación “Ejecutar este programa como administrador” y presionamos el botón “Aplicar”

Por último el botón “Aceptar”

Este mismo procedimiento lo hacemos para el Monitor de Tomcat 7, que es el archivo tomcat7w.exe también dentro del subdirectorio \bin


También lo aplicamos para todos los usuarios como se muestra.

Luego de aplicar aceptar podemos hacer la prueba reiniciando Windows y se notará que se ha solucionado el inconveniente.

Ahora intentamos iniciar NetBeans 6.8 y veremos que también ha sufrido por la actualización de Java si presionamos el botón “No” se cerrará, si presionamos, “Sí” nos saldrá la siguiente imagen si presionamos “Exit” se cerrará, si presionamos “Disable Modules and Continue” NetBeans iniciará de manera limitada como lo indica una imagen similar (NetBeans versión 6.9.1). Para solucionar este inconveniente debemos editar el archivo netbeans.conf que está dentro del subdirectorio \etc del directorio de instalación de Netbeans, al que le editamos la línea para indicar la nueva ruta del JDK como detalla la imagen.

Ahora voy agregar Apache Tomcat a Nebeans 6.8.
Con NetBeans iniciado, en el menú principal elegimos Tools y luego Servers Como vemos no tenemos a Tomcat en NetBeans presionamos “Add Server” Elegimos el tipo de instalador Tomcat 6.0 Disponemos ahora la ruta del folder de instalación de Tomcat, el usuario y la clave respectiva que se dispuso en el momento de su instalación, finalmente presionamos “Finish”. luego de que son reconocidos los puertos presionamos el botón “Close”. Como instalamos a Apache Tomcat con el asistente de Windows, éste no provee los archivos catalina.bat y setclasspath.bat necesarios para NetBeans que deberían estar dentro del subdirectorio \bin dentro del directorio de instalación de Tomcat. Para solucionar esto descargué la versión .zip de Apache Tomcat 6.0.29 y copié los archivos solicitados dentro del subdirectorio \bin de Tomcat. Luego de esto podemos iniciar o detener a Tomcat desde NetBeans.

Nuevamente se agregará a Tomcat funcionando en otro puerto, aprovechando que tenemos la versión .zip de Apache Tomcat 6.0.29, lo descomprimimos en una carpeta llamada \Tomcat II dentro del folder ServerWeb.  Posteriormente editamos el archivo server.xml que está el subdirectorio \conf dentro de \Tomcat II.
Primero buscamos la línea relacionada con el puerto del servidor 8005 y lo cambiamos a 8006 en la línea 22. Luego cambiamos el puerto 8009 a 8010 y 8443 a 8444 en la línea 90. Por último cambiamos el puerto 8080 a 8081 en la línea 69 y el puerto 8443 a 8444 en la línea 71. Después de configurado el nuevo Tomcat, se podrá agregar nuevamente a NetBeans tal como se explicó anteriormente y desde allí arrancarlo o detenerlo. Este funcionará en http://localhost:8081/

Ahora voy a agregar a MySQL a NetBeans 6.8.
Con NetBeans iniciado, en el menú principal elegimos Window y luego Services En MySQL le damos click secundario y elegimos “Properties” para establecer los parámetros respectivos… Establecemos la constraseña en “Administrator Password” en la pestaña “Basic Properties” Luego en la pestaña “Admin Properties”.
En “Path/URL to admin tool:” disponemos la ruta de instalación de la herramienta de administración de MySQL, que en nuestro caso es MySQL Workbench 5.2.30 CE.
En “Path to start command” disponemos al archivo mysqld.exe que está dentro del subdirectorio \bin del directorio de instalación de MySQL. En “Arguments” dispuse “–console” ya que si lo dejaba vacío no arrancaba MySQL.
En “Path to stop command” disponemos el archivo mysqladmin.exe también dentro del subdirectorio \bin del directorio de instalación de MySQL.
En “Arguments” de “Path to stop command” he dispuesto:
-u root -pXXXXXXXX shutdown” donde XXXXXXXX es el password real del root. Ahora para arrancar a MySQL Workbench 5.2.30 CE le damos click secundario a MySQL y luego “Run Administration Tool” para operar las bases de datos de MySQL.

Ahora actualizaré NetBeans de 6.8 a 6.9.1. Parece que el procedimiento estuviese alrevés, pero la idéa es explicar algunos procedimientos independiente de que versión estemos usando. Descargué NetBeans 6.9.1 para Windows. Arrancamos el asistente de instalación… Aparecerá la bienvenida del asistente y definimos lo que deseamos instalar presionando el botón “Customize” Como por ahora no deseo hacer cambios y ya tenemos Tomcat instalado, no hacemos ninguno en la instalación propuesta, presionamos “OK”. Aceptamos el acuerdo de licencia marcando la casilla de verificación y presionamos el botón “Next” Definimos la ruta del folder de instalación de NetBeans 6.9.1 y seleccionamos la ruta en la que está instalado el JDK de Java y presionamos el botón “Next” Luego establecemos donde queremos que se instale GlassFish 3.0.1, que por ahora no modificaré, por lo que presionamos el botón “Next” Comenzará el proceso de instalación Luego de que el asistente complete el proceso de instalación podemos presionar “Finish”, indiferentemente si deseamos o no registrarnos o contribuir al proyecto NetBeans. Nos preguntará si deseamos importar las disposiciones creadas en la versión anterior de NetBeans (6.8). Luego podemos arrancar a NetBeans 6.9.1 para finalizar mostramos el aspecto de NetBeans 6.9.1

Si por alguna circunstancia, NetBeans no arranca, entonces recomiendo borrar o renombrar la carpeta:
c:/Documents and settings/usuario/.netbeans

Otro de los incovenientes encontrados con cambios de versiones de NetBeans es la asociación de archivos a él. Uno de los motivos es que no se actualiza el registro de Windows a la actualización que se ha realizado a NetBeans. Esto se puede comprobar al tratar de “Elegir el Programa Predeterminado” para un archivo por ejemplo .jsp o .php, si NetBeans no está dentro de las opciones elegibles y al tratar de establecerlo manualmente buscándolo en la ruta de instalación no se añade como una opción es un signo de dicho inconveniente. Para solucionar este problema hacemos uso del regedit buscamos la palabra netbeans y borramos los registros que indiquen la versión anterior de NetBeans, en mi caso borramos los registros cuyo valor sea “NetBeans 6.8” sobre todo las claves:
[HKEY_CLASSES_ROOT\Applications\netbeans.exe\shell\open\command]
@”=”\”C:\\Program Files\\NetBeans 6.8\\bin\\netbeans.exe\” \”%1\””
[HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache]
“C:\\Program Files\\NetBeans 6.8\\bin\\netbeans.exe”=”netbeans.exe”
Con esto podemos asociar los archivos que queramos a NetBeans, en este caso será NetBeans 6.9.1.

Ahora mostraré como agregarle Java SE Development Kit Documentation 6u22 a NetBeans 6.9.1. Descargué la versión jdk-6u22-docs.zip. Teniendo NetBeans abierto, en el menú principal elegimos Tools y luego Java Platforms Se abrirá el “Java Platform Manager”. Elegimos la pestaña “Javadoc” y presionamos el botón “Add ZIP/Folder”… Buscamos la ruta del archivo Java SE Development Kit Documentation 6u22 descargado y elegimos jdk-6u22-docs.zip para agregarlo… finalmente en “Java Platform Manager” presionamos el botón “Close”…
Con esto podemos contar con la documentación en línea cuando estemos desarrollando aplicaciones basadas en Java.

Por ahora hemos finalizado la tarea de instalar y actualizar las diferentes herramientas y aplicaciones de Software propuestas desde el principio.

Publicado en Apache, databases, Httpd, Java, JSP, MySQL, Netbeans, PHP, RTF, Servidores Web, Software, Tomcat, Web Server, Windows | Etiquetado , , , , , , , , , , , , , , , , , , , , , , | 7 comentarios