martes, 7 de octubre de 2008

Upload behavior: para subir archivos (CADUCADO)

CADUCADO: La información de este post apesta por lo vieja. Es posible que ya no sea válida con las versiones más recientes de CakePHP. Se mantiene público  para vergüenza y escarnio del autor.

Aunque no está del todo terminado, lo cierto es que este behavior funciona bastante bien. Básicamente sirve para gestionar la subida de archivos por un formulario. Para usarlo, en el modelo tenemos que poner:

var $actsAs = array ('Upload' => array ('imagen' => array ('ruta' => 'test')));

Upload es, por supuesto, el nombre del behavior.

Imagen, en este caso, es el nombre del campo en el que se sube el archivo. Si vamos a poner varios campos para subir archivos, tendríamos que indicarlos como pares "campo" => "opciones". En el ejemplo, la opción ruta nos permite especificar una ruta específica (bajo el directorio base por defecto) para guardar los archivos subidos mediante ese campo.

Las opciones para cada campo son varias y vienen explicadas en el código, en la definición de var $opcionesDefecto y también un poco más abajo.

No tienes que hacer nada más. El behavior se dispara en el beforeSave. CakePHP pone el array de datos de un archivo recién subido en el campo del modelo. Upload behavior mira a ver si hay algún campo del modelo que contenga ese tipo de estructura y en caso afirmativo lo procesa. Si hay otro tipo de información, simplemente lo ignora.

Una cosa importante es que este behavior puede alterar el nombre del archivo. Si éste contiene caracteres que puedan dar problemas según los servidores, los "sanea". De este modo se previenen problemas posteriores de archivos correctamente subidos que luego no se pueden descargar y similares.

Opciones por archivo subido

Que conste que el código parece complicado porque intento poder gestionar muchas cosas:

  • modo: distintos modos de trabajar con el archivo recién subido. Los modos son : url para indicar que se sube el archivo a una ubicación y el campo se trata como una url para acceder a ese archivo (ideal para imágenes o descargas); ruta para indicar que se sube un archivo y el campo se trata como una ruta del sistema de archivos; contenido es para copiar el contenido del archivo en un campo especificado del modelo. En el futuro podría haber soporte para un modo más: bd, que serviría para almacenar la información en una base de datos, pero para eso hay que crear el modelo y algunas cosas más.
  • ruta: especificar una ruta específica para guardar el archivo que hemos subido.
  • mime_permitidos: controlar qué archivos se pueden subir por su tipo mime general o específico (p.ej, podríamos usar image, o bien image/jpeg). Si no se especifica nada, entonces no se controla este tema.
  • ext_permitidas: controlar qué archivos se pueden subir por su extensión. Si no se especifica, se admite cualquiera.
  • sobreescribir: si existe un archivo con el mismo nombre: true lo machaca.
  • crear_ruta: crea las carpetas necesarias.
  • campo_contenido: copia el contenido del archivo al campo especificado.

El código

Para pegar en /app/models/behaviors/upload.php
Bueno, he cambiado el código y lo he puesto aquí, para que sea más fácil leerlo y descargarlo y también más fácil de mantener actualizado.

11 comentarios:

Anónimo dijo...

Muchas gracias por el codigo y la explicacion....a ver si saco un poco de tiempo para mirarmelo con calma...
Una pregunta, este codigo sirve para subir la imagen a las base de datos? o es solo para un directorio?

Animo con el blog...

Frankie dijo...

Si pones la opción "modo" en "contenido" y especificas un campo del modelo (tipo blob en mysql) pues se consigue eso que quieres.

Otra cuestión es la eficiencia de eso. Yo, normalmente, prefiero subir el archivo al sistema de archivos y guardar la referencia en el modelo, en lugar del contenido. Pero es cuestión de gustos o de necesidades.

Anónimo dijo...

Acabo de descubrir el blog y llevo un buen rato leyendo desde la primera entrada.

Respecto a esta entrada, a parte de agradecer el código y el razonamiento, me has hecho recordar un comentario que me hicieron una vez....."No olvides que el sistema de archivos está diseñado y optimizado para almacenar archivos. Que mejor sitio para guardarlos?"

Saludos,
Juanra

Arantxa dijo...

Buenas. Gracias por el blog, nos sirve de guía a muchos.
Te quería comentar, que, como posible mejora, podías añadir la opción 'nombre' al modo, para que así, el valor que devuelve es el nombre del archivo, sin rutas ni nada. Además, también sería útil la opción de prefijo/sufijo para el nombre de los archivos, o poder renombrar los archivos con, el id del registro, por ejemplo...
Son sugerencias, y, creo que todo el que ande por aquí, sabrá hacerlo sin problema, pero ya que el código es tuyo... bueno, eso.
Gracias por todo.

alejandro_miguel dijo...

hola, parece muy util el Behavior
pero diganme como lo utilizo
dentro del modelo, el controller y la vista
o es q automaticamente leera los archivos al usar en mi formulario el tipo $form->file('Tabla/campo')
y realizara el proceso dela carga de los archivos

gracias

Frankie dijo...

En el modelo se pone:

var $actsAs = array ('Upload' => array ('imagen' => array ('ruta' => 'test')));

siendo imagen el campo del modelo que queremos que reciba el archivo (o su url).

En la vista basta poner un campo tipo file, como dices. En principio no hay que hacer nada más, las opciones van explicadas en el propio cóidgo. Estoy trabajando en una versión actualizada, pero tardará un poco.

Manuel dijo...

Hola, estoy usando el behavior y queria hacerte una consulta:
Quiero modificar el nombre del archivo una vez que el sitio lo sube, asi no tengo problemas con nombres repetidos, el problema es que no se como (ya me sube fotos, pero tienen que ser de nombre distinto, sino no me deja).
Estoy usando el actAs asi:
var $actsAs = array ('Upload' => array ('photo'));

la pregunta es: ¿Que otra opción tengo que ponerle para que automáticamente me modifique el nombre del archivo?

Muchas gracias

Frankie dijo...

@Manuel, actualmente no lo modifica, habría que añadir un poco de código para generar un nombre nuevo.

Manuel dijo...

Ok, tenia pensado hacerle alguna funcion que le ponga al archivo el ID del registro que se esta grabando.

Soy muy nuevo con cake pero si puedo hacer algo se los paso

Saludos

Buen Venezolano dijo...

Saludos estoy probando el Upload behavior

Me inserta los datos ne la base de datos pero no me sube el archivo estoy trabajando en windows

no me muestra ningun error

que hago?

Frankie dijo...

Habría que ver si tienes permisos de escritura en la carpeta de destino y cabe la posibilidad de que haya algún problema con el separador de directorios de windows (\).