Mostrando entradas con la etiqueta upload. Mostrar todas las entradas
Mostrando entradas con la etiqueta upload. Mostrar todas las entradas

jueves, 17 de septiembre de 2009

Sobrecargando el campo upload

Repasemos un momento.

En PHP, cuando tienes uno o varios campos tipo "file" para subir archivos en un formulario y éste es enviado al pulsarse un botón Submit, PHP coloca los datos de los archivos subidos en el array $FILES. No tenemos más que ir a buscar allí los datos, hacer las comprobaciones necesarias y usar move_uploaded_file() para poner los archivos en los lugares adecuados.

CakePHP va un paso más allá y coloca esos datos en los campos adecuados del array de datos que viene del formulario, lo que hace aún más fácil usarlos. En concreto, el array asociativo que nos da la información de cada archivo tiene estas claves:

tmp_name
name
type
size
error

Y ahora, el truco:

Supongamos que tenemos un Modelo con un campo file con el que vamos a subir un archivo. Por tanto, en la vista en la que construimos el formulario ponemos algo así como:


echo $form->input('Modelo.file', array('type' => 'file'));


Resulta que si ponemos un campo del estilo de:


echo $form->input('Modelo.file.extra');


Cuando hagamos el proceso del archivo subido nos vamos a encontrar más claves en el array de información, exactamente tantas como campos Modelo.file.* hayamos creado:

extra

tmp_name
name
type
size
error


¿Útil? Puede que sí. Gracias a este pequeño truco he podido crear un formulario en el que el usuario puede marcar que sea borrado un archivo ya existente, si no quiere subir otro para que lo sustituya.

martes, 11 de agosto de 2009

Usando Media View para descargar archivos

Estoy trabajando en un plugin para gestionar archivos subidos a una aplicación web y entre otras cosas he aprendido a utilizar las Media Views para facilitar las descargas de esos mismos archivos, estén almacenados donde estén.

La documentación base que he utilizado es la página del manual y un post del siempre recomendable blog sobre CakePHP de Teknoid. A partir de aquí, y tras unas pocas pruebas parece que he conseguido dominar este tipo de vistas.

Qué es una Media View

Se trata de un tipo de vista especial para enviar archivos binarios al usuario. Se utiliza en lugar de las vistas por defecto y la verdad es que se encarga de casi todo ella solita.

Hay dos ventajas principales en usar MediaView en lugar de enlaces directos al archivo:

  • Podemos enviar archivos que no estén bajo el webroot, evitando así que los usuarios puedan descargarlos reconstruyendo la URL, algo relativamente fácil conociendo cómo funciona CakePHP
  • Al realizar la descarga a través de una acción de un controlador, ésta puede tener el acceso controlado a través de Auth o el método que tengamos, con lo cual, incluso con la URL sólo los usuarios autorizados podrían descargar el archivo.
Empleando Media View

Para poder empezar a utilizarlas debemos especificarlo en la acción apropiada del controlador, con la siguiente línea:

$this->view = 'Media';

A continuación hay que pasarle varios parámetros para identificar el archivo, una forma sencilla sería así:

$params = array(
'id' => 'nombre_del_archivo.ext',
'name' => 'Nombre Humano del Archivo',
'download' => true,
'extension' => 'ext',
'mimeType' => array('ext' => 'mimeType/subtype'),
'path' => 'path/a/la/carpeta/del/archivo/',
);
$this->set($params);

Trataré de explicarme:

Empiezo por el final. A la vista habría que pasarle los parámetros id, name, etc. Pasando un array con las claves necesarias hacemos lo mismo. A mí al principio me extrañó esta manera de hacerlo (lo típico es pasar $this->set('params', $params);) pero al ver el código de media.php, me quedó claro que CakePHP desempaqueta el array. En consecuencia, puedes ponerle al array el nombre que quieras, no hace falta que sea $params mientras que las claves sean correctas.

Ahora voy por los parámetros o claves del array.

id: Es el nombre del archivo que vamos a enviar, tal cual está en el sistema de archivos.

name: Es el nombre con el que queremos que el usuario guarde el archivo en su disco duro, esto nos permite ponerle un nombre humanizado si preferimos.

extension: Se explica solo, es la extensión del archivo

download: si está en true, fuerza la descarga el archivo

mimeType: esta parte tiene truco. A mí me costó un poquito cogerle el punto. La clase MediaView "reconoce" una buena cantidad de tipos mime que podrían tener los archivos, pero no todos. El problema es que no se descargan si no proporcionamos el mimeType correcto. Afortunadamente, en esta clave podemos declarar uno o más mimeType aceptables para cada archivo concreto. La forma de declararlos es poner la extensión como clave y como valor el tipo mime. En mi caso, al subir el archivo tomo nota del mimeType y no tengo más que recuperarlo en la acción de descarga y pasarlo en esta clave. De este modo me ha permitido descargar diversos tipos de archivos que MediaView no admitía (como los .rar).

path: es la ruta al archivo relativa a la carpeta de la aplicación (concretamente utiliza el valor de la constante APP), por lo cual, podemos descargar archivos que no estén bajo el webroot, sino en un nivel superior y fuera de él. Esto es ideal si no queremos que los usuarios puedan descargar archivos "imaginándose" la URL. Debe llevar el separador de directorios al final. Recuerda construir los paths usando la constante DS si necesitas que la aplicación sea portable.

size: se puede especificar la clave size para indicar el tamaño de archivo, pero yo no he conseguido que los archivos se descargasen. No sé dónde esta el error.

Y ya está.

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.