Mar 25

Subir ficheros al servidor con JSP

 Dentro de la aplicación web que estamos haciendo, tenemos que permitir al usuario subir ficheros al servidor. Sé cómo se suben ficheros al servidor en PHP, pero nunca lo había hecho con JSP. Pensé que sería similar, pero me he encontrado con algunas sorpresas.

La primera sorpresa ha sido buscando en google. Unas búsquedas rápidas no me ha dado ningún resultado en el que se suba el fichero sin necesidad de librerías adicionales. Pensé que sería igual que con Apache/PHP, el servidor sube el fichero a una carpeta temporal y una variable le indica a nuestra aplicación PHP dónde está. En Tomcat/JSP parece ser que no es así. Insisto, quizás sí, pero no he buscado en profundidad.

Todos los resultados de google que he visto hacen referencia a que hay que usar alguna librería externa, como apache-commons-fileupload. Así que me puse a ello, usando esa librería.

La segunda pega es que al ser el form de html enctype="multipart/form-data", necesario para poder subir un fichero, en la parte del servidor JSP dejan de funcionar los request.getParameter(), siempre devuelve null. Resulta que si el request es multipart/form-data, hay que tratarlo de otra manera. Este asunto me ha llamado la atención y le ha hecho perder un puntito a JSP frente a PHP (o a Tomcat frente a Apache, no sé quién es el culpable), donde parece que  no hay esos problemas.

¿Y cómo se leen entonces los parámetros de la petición?. Pues nuevamente una búsqueda rápida en google parece indicar que la única solución es usar librerías externas y en concreto, la misma apache-commons-fileupload. Con esa librería se "parsea" la petición y obtenemos una lista de FileItem. Cada uno de ellos puede ser un fichero al que se ha hecho upload…. ¡¡ o uno de los parámetros !!. Llamando a los método getFieldName() y getString() (comprobando previamente si es parámetro o fichero) de esos FileItem obtenemos los valores.

En fin, algo que me ha parecido rebuscado y demasiado complejo frente a cómo se hace en PHP/Apache. Un pequeño tutorial de esto en la chuwiki: File Upload con JSP.

Apr 23

¿JSP o PHP?

 

Esta es una pregunta bastante habitual en la gente que empieza a hacer aplicaciones web o, incluso en la gente que ya lleva tiempo en uno de esos dos lenguajes y se plantea si merece la pena pasarse al otro. No pretendo aquí dar una relación exhaustiva de los pros y contras de cada uno de ellos, pero sí algunos de los puntos que considero importantes a la hora de decidirse.

Librerías disponibles

Tanto un lenguaje como otro tienen muchísimas librerías disponibles para hacer un montón de cosas. JSP/Java tienes bastantes más, pero también es un lenguaje multi-propósito, por lo que muchas de ellas no nos servirán para nada en una aplicación web. PHP está más pensado para web y todas sus librerías son útiles para web. Por ello, lo único que debemos tener en cuenta en este punto concreto es qué librerías vamos a necesitar para nuestras aplicaciones y si las tenemos disponibles en el lenguaje que vayamos a elegir. En su defecto, qué nos costaría desarrollar esa misma librería.

Hospedaje en el servidor

La aplicación web debe ir en un servidor. Normalmente es más fácil encontrar servidor PHP con base de datos gratuitos que servidores que ofrezcan JSP/Servlets gratuitos. Si vamos a los de pago, también es más fácil y barato encontrar servidores PHP. Por ello, si el coste es un problema, posiblemente PHP sea mejor opción.

Si nuestra aplicación web está pensada para que la gente en general la use y la instale en sus servidores (por ejemplo, un blog estilo wordpress, una wiki estilo Mediawiki, etc), también tendrá más aceptación posiblemente si la hacemos en PHP, ya que de todos esos posibles webmaster que queremos que usen nuestra aplicación, la mayoría tendrán PHP pero no JSP.

Si nuestra aplicación es para uso particular en una empresa o en casa y el servidor nos lo vamos a montar nosotros mismos, en principio no hay ningún problema con un lenguaje u otro. Es prácticamente igual de fácil instalar, por ejemplo, un servidor Apache con PHP que un servidor Tomcat para JSP/Servlets.

La aplicación y el lenguaje en sí mismos

Entre los lenguajes Java y PHP hay una diferencia que considero fundamental. El primero es tipado, es decir, hay que declarar los tipos de las variables, los parámetros de los métodos, etc, etc. En PHP no hay tipado, se pueden usar las variables sobre la marcha y pueden contener cualquier cosa en momentos distintos de la ejecución. Java es 100% orientado a objetos, mientras que PHP permite mezclar clases con funciones de programación estructurada. Esta diferencia hace que según el tipo de aplicación, sea mejor un lenguaje u otro.

Si nuestra aplicación es una aplicación puramente web, en la que principalmente hay presentación en navegador y transacciones con una base de datos, en la que van a participar un número de desarrolladores no muy grande y el tiempo de desarrollo no muy largo, PHP puede ser una buena opción.

Sin embargo, en aplicaciones muy grandes, en la que pueda haber más código/algorítmica aparte de lo estrictamente presentación en navegador y transacciones en base de datos, va a haber muchos desarrolladores y tiene un tiempo de desarrollo largo, es mejor usar JSP/Servlets.

Y explico el motivo. Una función PHP puede parecerse a esto

function la_funcion ($el_parametro) {
   $el_resultado = ….
   return $el_resultado
}

mientras que un método similar en Java puede ser como este

public TipoResultado laFuncion (TipoParametro elParametro) {
   TipoResultado resultado = …;
   return resultado;
}

Mientras estamos codificando y con el código en la cabeza, casi da igual una cosa que otra. Pero si ese código no lo he hecho yo y tengo que mantenerlo o usarlo, o lo he hecho yo pero hace unas semanas, el código PHP no ayuda en absoluto a saber qué tipo de parémetro hay que pasar o qué devuelve (ni siquiera si devuelve algo), habría que leer el código interno de la función con detalle. El código Java, sin embargo, deja claro qué tipo espera como parámetro y qué devuelve, así que quizás no tengamos que mirar el código interno del método para usarlo.

El no saber los tipos de entrada/salida puede resolverse con una disciplina estricta y comentarios adecuados, pero recuerda, estamos hablando de un grupo de desarrolladores grande. En un grupo grande, siempre hay  un porcentaje importante de ellos que será poco disciplinado/novatos y pondrán comentarios graciosos.

Hay además otras dos ventajas fundamentales en los lenguajes tipados:

  1. Los IDE tienen un autocompletar mucho mejor. Cualquier IDE de java moderno, pones la variable, un punto y te saca los posibles métodos/atributos a los que puedes llamar. Un buen IDE de PHP lo intentará, pero no siempre lo conseguirá. En el ejemplo anterior, si en java escribimos elParametro., el IDE nos pondrá los posibles métodos porque sabe que elParametro es de tipo TipoParametro. En PHP, poniendo el_parametro->, el IDE no nos puede poner absolutamente nada, porque no sabe de qué tipo es eso.
  2. Precisamente por eso y por la necesidad de declarar los tipos, un IDE no nos dejará, por ejemplo, llamar a un método que no existe o asignar a una variable no declarada. PHP sí nos dejará hacerlo o nos dejará, por ejemplo, poner $nuemro (me he equivocado a posta, en vez de $numero he puesto $nuemro) y declarar sin querer una nueva variable. Todo esto fallará, si tenemos suerte, cuando hagamos nuestra ejecución. Pero si no tenemos suerte, errores de este tipo no saltarán al ejecutar, el programa símplemente no dará el resultado esperado y perderemos horas de depuración. En java directamente no compilará y el IDE nos cantará el error en cuanto lo escribamos.

Así que si la aplicación es grande y con muchos desarrolladores, es posiblemente mejor usar un lenguaje tipado.

Gustos personales

Finalmente, cómo no, los gustos personales de cada uno, las prisas, ganas de aprender, etc. Alquien puede tener preferencia por uno de los lenguajes, o bien ser el que domina y no querer meterse en el otro, o bien todo lo contrario, querer meterse para aprender. Si vas a hacer una aplicación web sencilla, pero dominas java, tienes prisa en hacerla y te importa tres pepinos PHP, posiblemente la hagas en JSP, aunque alguien que domine PHP quizás tardaría menos en hacerla en PHP.

En resumen

Supongo que al menos parte de estas razones son las causas principales por el que en el ambiente de internet al público, la mayoría de las aplicaciones son PHP (wordpress, mediawiki, etc), mientras que las aplicaciones JSP/Servlets se quedan más para ambientes empresariales o intranets. Ojo, hay cosas de ambos tipos en ambos ambientes, símplemente estoy indicando lo que parece ser mayoría.

¿A alguien se le ocurren más motivos a tener en cuenta?

Apr 25

sitemap para SMF

Hace tiempo comenté en un post que el foro SMF es un desastre para que lo indexe google y, de hecho, no aparecía en google ninguno de los temas de mi foro de java. Intenté instalar el plugin seo4smf para tratar de arreglarlo, pero no conseguí que me funcionara. Al final, como comenté en aquel post, me hice un pequeño programa java que generara un fichero sitemap.xml para colgarlo en el foro.

Esa opción no era buena del todo. Conseguí que google indexara los temas del foro, pero tenía que actualizar el sitemap periódicamente a mano. Así que decidí hacerme un pequeño script sitemap.php que hiciera de sitemap para google de forma automática.

Este script, al llamarlo, consulta en la base de datos el campo id_topic de la tabla smf_topics. Es la única información que necesita para generar el fichero XML de sitemap. El script dice que devuelve un "Content-Type : application/xml" para que cuando google lo consulte piense que es un fichero XML, luego envía los tags XML correspondientes al sitemap.

Adjunto el código php por si a alguien le interesa

<?php
header(‘Content-Type: application/xml’);
include (‘Settings.php’);

print (‘<?xml version="1.0" encoding="UTF-8"?>’);
print (‘<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">’);

$link = mysql_connect ($db_server, $db_user, $db_passwd) or die ("<center>No se puede conectar con la base de datos\n</center>\n");
$query=’select id_topic from smf_topics’;
$result=mysql_db_query ($db_name, $query, $link);

while ($row = mysql_fetch_array ($result))
{
   print (‘<url>’);
   print (‘<loc>’);
   print (‘http://foro.chuidiang.com/index.php?topic=’.$row[0]);
   print (‘</loc>’);
   print (‘</url>’);
}
mysql_free_result($result);
print (‘</urlset>’);
?>

El include "Settings.php" únicamente incluye un fichero de configuración del foro, en el que están las variables con el nombre de la base de datos $db_name, el usuario $db_user y la password $db_passwd. Ojo, no le busqueis pegas, que las tiene. Yo no tengo ni idea de PHP.

 

Aug 17

Impedido para programar

Siempre que me pongo a programar, aunque sea una tontería, me pasa lo mismo. Me quedo bloqueado.

Como comenté en un post anterior, estoy haciendo un pequeño programa PHP para que la gente pueda apuntar en qué proyectos trabaja durante el mes y cuánto tiempo dedica a ello. Cosas del trabajo.

Me puse a ello. Lo primero, una tabla de base de datos para apuntar a los programadores y una serie de páginas php para que se puedan registrar, hacer login y, por supuesto, para que el administrador pueda administrar esa tabla: añadir, borrar y modificar usuarios.

Todo estupendo hasta este momento.

Iba a ponerme ahora con otra tabla de base de datos en la que se apunten los proyectos en marcha. Por supuesto hay que hacer otra serie de páginas php para administrar esa tabla: crear, borrar o modificar proyectos.

Ahí me he quedado bloqueado.

Es otra vez lo mismo. Otra tabla a la que  hay que hacerle nuevamente tres páginas php para lo mismo de antes, altas, bajas y modificaciones. Lo más cómodo, copy/paste de las de usuarios e ir modificando. Pero copy/paste desde mi punto de vista ¡¡es pecado!!. El código no debería repetirse. Hay que hacer lo posible por extraer lo común a una función o grupo de funciones y reutilizarlas.

Rápidamente, me puse a darle vueltas a la cabeza. Tendría que hacer unos ficheros de configuración que digan cómo son las tablas -o bien mirar directamente los metadatos de la base de datos- y luego hacer tres funciones que me den la página de alta, baja y modificación simplemente pasándoles el nombre de la tabla y qué campos son el identificador principal de la tabla. Seguramente sea necesario algún parámetro más.

Esto, por supuesto, lleva más tiempo que un copy/paste y hacerlo todo a piñón fijo, repitiendo el código cada vez que se presente una tabla. También es más versátil. Si se hace bien, te ahorrará un montón de trabajo cada vez que tengas que hacer una tabla con añadir, borrar y modificar. En contra, también, que el código resultante será mucho menos claro.

Y en eso estoy.

Una aplicación que me podía llevar una o dos semanas a ratos libres -estoy de vacaciones-, me va a llevar:

  • unos días para hacer la primera tabla
  • otro día para empezar la segunda tabla y ver que el copy/paste me vendría bien pero no quiero usarlo.
  • una semana entera para darle vueltas a si hago o no hago la cosa esa común/reutilizable para no utilizar el copy/paste.
  • otras dos semanas para ponerme a hacerla y meterme en complicaciones.
  • un minuto para mandarlo todo a la mierda. No acabaré el común/reutilizable porque es más complejo de lo que parece y no hago el copy/paste porque es pecado. La aplicación y yo nos quedamos bloqueados.
  • Varios meses para estar pensando: "debería acabar eso que tengo a medias…."

Pues eso, ahora mismo estoy en el punto 3, empezando la semana de darle vueltas a ver si hago o no la cosa común/reutilizable. Para este proyectito no merecería seguramente la pena, pero seguro que este proyectito no es el último.

¿No estais hasta las narices de hacer siempre lo mismo, una y otra vez tabla en base de datos, ventana de alta, de modificación y de baja?. ¿Haríais la cosa común/reutilizable?.

Aug 15

Hormiguillas en el culo

Últimamente parece que tengo hormiguillas en el culo. No paro quieto y ando saltando de un tema a otro.

Primero me puse con el tema de perl, para hacer mi conversor de lenguajes. Eso fue cosa del trabajo.

Luego estuve un par de semanas de Rodriguez en casa, sin familia, así que retomé lo de JSP. Tenía los taglibs un poco atascados por una tontería de Maven.

Ahora, de vacaciones, y a ratos perdidos, he retomado lo de PHP que dejé en su día. Estoy intentando hacer una pequeña librería PHP para la validación de sesiones y usuarios. La idea es que haya una serie de páginas PHP que permitan ver una lista de usuarios y añadir, borrar y modificar dichos usuarios. Esta parte está prácticamente acabada.

Luego, haré unas funciones PHP que se puedan llamar desde otra aplicación PHP y que permitan validar una sesión con uno de los usuarios. También se podrá además llamar al conjunto de páginas PHP de usuarios para gestionarlos.

Con esto tengo intención de hacer dos aplicaciones PHP:

  • Una para el trabajo, que permita a la gente poner cuántos días del mes han dedicado a qué proyectos.
  • Otra para mi página web, que permita añadir comentarios a los tutoriales. Ya la tengo hecha, pero si algún patán mete alguna burrada, el borrado dichos comentarios se hace manejando directamente la base de datos. Quería poner un usuario administrador -yo- que pueda borrar desde el navegador los comentarios de los patanes.

Pues nada, poco a poco y a ver si acabo alguna de ellas antes de que me pique otra hormiguilla en el culo. La del J2EE con EJBs anda por las cercanías ….

Aug 03

Puente PHP/Java

Alucino con lo que se inventa por ahí.

Urgando por la red me he encontrado con un puente PHP/Java. Básicamente es un añadido a PHP de forma que se puede llamar a clases de java desde PHP.

El manejo parece muy sencillo en la página. Simplemente se instancia una clase PHP llamada Java a la que se le pasa en el constructor como String el nombre de la clase Java. La clase PHP creada así tiene todos los métodos de la clase Java y a partir de ahí podemos usarla normalmente como PHP. Un ejemplo copiado de la página

<?php
$v = new Java("java.util.Vector");
$v->add($buf=new Java("java.lang.StringBuffer"));
$buf->append("100");
echo (int)($v->elementAt(0)->toString()) + 2;
?>

En fin, es una cosa que si me preguntan antes de verla diría que es imposible llamar desde php a java -salvo quizás alguna función php para lanzar ejecutables externos-. Va a haber que pensárselo dos veces antes de decir en programación que algo no se puede hacer.

Mar 03

¿PHP o Java/JSP?

¿Qué usamos? ¿PHP o Java con JSP?

Un posible criterio es decidir si tenemos una aplicación con web o una web con aplicación. ¿Qué quiere decir esto?

Si tenemos una aplicación con web, es decir, unos datos más o menos complejos que requieren un tratamiento más o menos complejo y los resultados vamos a presentarlos en un navegador, entonces tenemos una aplicación con web. Para esto es adecuado Java/JSP. Java nos da la potencia necesaria para hacer la parte de aplicación, mientras que presentamos los resultados en el navegador con JSP. Este puede ser el caso, por ejemplo, de una gestión de empleados con nominas, contabilidad, gestión de stock en almacenes, … que ponemos accesibles desde navegador. En fin, cualquier aplicación que tuviera sentido por sí misma como aplicación de escritorio.

Si tenemos una web con aplicación, básicamente estamos haciendo una web en la que necesitamos algo de código para guardar datos en base de datos o hacer algún que otro proceso sencillo de código para presentar esos datos. Este es el caso típico de los foros, los blogs, etc, etc. Para esto es adecuado PHP.

Visto en Jarfil’s Blog. Por cierto, está curioso el gatito de arriba a la izquierda de ese blog. Echale un ojo y luego puedes jugar con él clickandolo.

Feb 16

Imágenes aleatorias en PHP

Sigo jugando con PHP. Lo siguiente que se me ocurrió fue poner un chiste aleatorio en mi página. Así que cogí unos cuantos chistes de internet (esta es la parte divertida) y los guardé en un directorio en el servidor de mi página. Luego a investigar con php cómo se lee el contenido de un directorio para poner la imagen.

Me encontré con la función scandir(), que te devuelve un array con los nombres de los ficheros dentro del directorio. También devuelve los subdirectorios "." y "..".

A partir de ahí fué fácil, simplemente llamar a rand (2, $numeroFicheros). Lo de 2 para que se salte el 0 y el 1 que corresponden a los dos subdirectorios "." y "..". List todo. Lo pruebo en mi ordenador con mi propio servidor web de prueba y va estupendamente. Lo subo a mi servidor oficial, lo prueba y no va.

Una cosa que me llama poderosísimamente la atención es lo fácil que es todo en la teoría y como se complica la realidad. Me pongo a investigar y resulta que scandir() está disponible a partir de PHP 5. En casa tengo PHP 5, en el servidor del hosting tengo PHP 4. A buscar más.

Al final encontré la función glob(), a la que le pasas un patrón, estilo "imagenes/*" y te devuelve todos los ficheros que cumplen el patrón. No es lo mismo que scandir(), pero vale perfectamente. Esta función si es válida …. a partir de PHP 4.3.0 … Me voy al servidor, con más miedo que verguenza, a ver qué versión exacta tiene, no vaya a ser …  ¡¡Buff!!, tiene la 4.4.4.

glob() no devuelve los subdirectorios "." y "..", así que a cambiar el rand() por rand(0,$numeroFicheros)

Al final el código PHP quedó así

<?php
        $fichero = glob (‘chistes/*’);
        $chiste = rand(0,count($fichero)-1);
        print(‘<img src="’.$fichero[$chiste].’" alt="chiste" /> ‘);
?>

Feb 14

Resuelto mi php

Ya he terminado mi experimento con php. En mi página ya se pueden añadir comentarios al final de cada artículo y funciona todo (creo).

Aunque me ha costado un poco, porque no tengo ni idea de php, he aprendido algunas cosas. Aquí un pequeño resumen

  • El  usuario y password de la base de datos se guardan como dos variables en un fichero .php en algún sitio que no esté accesible desde el navegador, protegido con un .htaccess o simplemente fuera del directorio del sitio. No sé si es muy necesario, pero supongo que nunca está de más ser algo paranoico con la seguridad.
  • Cuando se deja libertad a los visitantes para escribir texto que luego se va a insertar en base de datos o mostrar en el navegador, conviene escapar las comillas. PHP lo tiene más o menos resuelto con funciones del estilo addslashes() que hacen eso precisamente, poner una \ delante de las comillas. Hay un detalle con esto. PHP se puede configurar para que automáticamente añada las \ delante de las comillas en todas los contenidos que lleguen con $_POST o $_GET. Si esto es así, no debemos añadir nosotros más \. Para verificar esto, está la función get_magin_cuotes_gpc(), que nos devuelve 1 si PHP va a añadir automáticamente las \.
  • Pasa lo mismo con los caracteres que html interpretará luego, como <, >, o los que no son válidos, como letras con acentos, eñes y demás. PHP también tiene una función para esto: htmlspecialchars()
  • Cuando recogemos una fecha/hora de base de datos, el formato obtenido no le gusta a PHP. Para que sea más compatible, en el select de base de datos podemos poner "select UNIX_TIMESTAMP(fecha) as fecha, otrocampo from…" De esta forma, el resultado que obtenemos para fecha lo entiende perfectamente PHP.
  • Otra cosa que tuve que hacer es una página .php aparte que únicamente realiza la inserción en base de datos del comentario e inmediatamente después, con header(), redirige a la página original. Esta página de inserción es a la que llaman los submit de los formularios. Con esto evito el problema que comenté en otro post al pulsar el refrescar del navegador. El header() debe usarse antes de enviar nada al navegador.

y creo que no se me olvida nada. A ver si lo apunto todo con algo más de detalle en algún sitio.

Feb 13

“PHPando”

Para jugar un poco con php primero hice una especie de contador en mi página web.

Cree una base de datos, añadí una tabla con varios campos: mes de la visita, año de la visita, número de visitas y página visitada. Todo sin problemas y está más o menos funcionando en mi sitio.

Ahora me he puesto a hacer algo más complejo. Estoy poniendo la posibilidad de que la gente añada comentarios a los artículos. Todo está funcionando bien… salvo una pequeño detalle que no consigo resolver.

Si una vez que alguien ha insertado un comentario, pulsa “recargar” en el navegador, vuelve a insetarse el mismo comentario. Aunque el formulario esté vacío, se ve que al recargar todavía se acuerda del contenido de $_POST[] y vuelve a insetar. Así que aquí ando, peleándome con varias posibilidades:

  • Detectar si es recarga de página para no hacer la inserción del comentario.
  • Viendo si hay forma de vaciar $_POST[] después de haber hecho la inserción
  • No me gustaría, pero quizás tenga que hacer una página intermedia que haga la inserción y luego redirija con header() a la original.
  • Y me gustaría todavía menos abrir una sesion con session_start() o similar. Creo que no puedo usar las variables $_SESSION[] si no abro una sesión y la sesión debe abrirse justo antes de enviar nada al navegador, por lo que tendría que volver a tocar TODAS las páginas (ya las cambié de html a php con hoja de estilo). No se me ocurrió hacer un <?php cabecera(); … al principio de todas

A ver si esta tarde lo acabo…