TigerZF
🌐Español

Capítulo 34. Zend_File

34.1. Zend_File_Transfer

Zend_File_Transfer proporciona un amplio soporte para la subida y descarga de archivos. Incluye validadores integrados para archivos, además de funcionalidad para modificar archivos con filtros. Los adaptadores de protocolo permiten que Zend_File_Transfer exponga la misma API para protocolos de transporte como HTTP, FTP, WEBDAV y otros.

[Note] Limitación

La implementación actual de Zend_File_Transfer está limitada a subidas mediante HTTP Post. Otros adaptadores que soporten descargas y otros protocolos se añadirán en futuras versiones. Los métodos no implementados lanzarán una excepción. Por ahora, debería usar Zend_File_Transfer_Adapter_Http directamente. En cuanto haya varios adaptadores disponibles podrá usar una interfaz común.

[Note] Formularios

Cuando use Zend_Form debería usar las APIs proporcionadas por Zend_Form y no Zend_File_Transfer directamente. El soporte de transferencia de archivos en Zend_Form está implementado con Zend_File_Transfer, así que la información de este capítulo puede ser útil para usuarios avanzados de Zend_Form.

El uso de Zend_File_Transfer es relativamente sencillo. Consta de dos partes. El formulario HTTP realiza la subida, mientras que Zend_File_Transfer gestiona los archivos subidos. Vea el siguiente ejemplo:

Ejemplo 34.1. Formulario sencillo para subir archivos

Este ejemplo ilustra la subida básica de archivos. La primera parte es el formulario de archivo. En nuestro ejemplo hay un archivo para subir.

<form enctype="multipart/form-data" action="/file/upload" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="100000" />
        Choose a file to upload: <input name="uploadedfile" type="file" />
    <br />
    <input type="submit" value="Upload File" />
</form>

Por conveniencia, puede usar Zend_Form_Element_File en lugar de construir el HTML manualmente.

El siguiente paso es crear el receptor de la subida. En nuestro ejemplo el receptor está ubicado en /file/upload. Así que a continuación crearemos el controlador 'file' y la acción upload().

$adapter = new Zend_File_Transfer_Adapter_Http();

$adapter->setDestination('C:\temp');

if (!$adapter->receive()) {
    $messages = $adapter->getMessages();
    echo implode("\n", $messages);
}

Este listado de código muestra el uso más simple de Zend_File_Transfer. Se establece un destino local con el método setDestination(), y luego se llama al método receive(). Si hay algún error de subida, se devolverá un error.


[Note] Atención

Este ejemplo es adecuado únicamente para demostrar la API básica de Zend_File_Transfer. Nunca debería usar este listado de código en un entorno de producción, porque podrían introducirse problemas graves de seguridad. Debería usar siempre validadores para aumentar la seguridad.

34.1.1. Adaptadores soportados para Zend_File_Transfer

Zend_File_Transfer está diseñado para soportar una variedad de adaptadores y direcciones de transferencia. Con Zend_File_Transfer puede subir, descargar e incluso reenviar (subir con un adaptador y descargar con otro adaptador al mismo tiempo) archivos.

34.1.2. Opciones para Zend_File_Transfer

Zend_File_Transfer y sus adaptadores soportan diferentes opciones. Puede establecer todas las opciones pasándolas al constructor o llamando a setOptions($options). getOptions() devolverá las opciones establecidas actualmente. A continuación se muestra una lista de todas las opciones soportadas.

  • ignoreNoFile: Si esta opción se establece en TRUE, todos los validadores ignorarán los archivos que no hayan sido subidos por el formulario. El valor por defecto es FALSE, lo que resulta en un error si no se especificaron archivos.

34.1.3. Comprobación de archivos

Zend_File_Transfer tiene varios métodos que comprueban diversos estados del archivo especificado. Son útiles si necesita procesar archivos después de que hayan sido subidos. Estos métodos incluyen:

  • isValid($files = null): Este método comprobará si los archivos dados son válidos, según los validadores adjuntos a los archivos. Si no se especifica ningún archivo, se comprobarán todos. Puede llamar a isValid() antes de llamar a receive(); en ese caso, receive() no llamará a isValid() internamente de nuevo al recibir el archivo.

  • isUploaded($files = null): Este método comprobará si los archivos especificados han sido subidos por el usuario. Es útil cuando ha definido uno o más archivos opcionales. Cuando no se especifica ningún archivo, se comprobarán todos.

  • isReceived($files = null): Este método comprobará si los archivos dados ya han sido recibidos. Cuando no se especifica ningún archivo, se comprobarán todos.

Ejemplo 34.2. Comprobación de archivos

$upload = new Zend_File_Transfer();

// Returns all known internal file information
$files = $upload->getFileInfo();

foreach ($files as $file => $info) {
    // file uploaded ?
    if (!$upload->isUploaded($file)) {
        print "Why havn't you uploaded the file ?";
        continue;
    }

    // validators are ok ?
    if (!$upload->isValid($file)) {
        print "Sorry but $file is not what we wanted";
        continue;
    }
}

$upload->receive();

34.1.4. Información adicional de los archivos

Zend_File_Transfer puede devolver información adicional sobre los archivos. Los siguientes métodos están disponibles:

  • getFileName($file = null, $path = true): Este método devolverá el nombre real del archivo de un archivo transferido.

  • getFileInfo($file = null): Este método devolverá toda la información interna del archivo dado.

  • getFileSize($file = null): Este método devolverá el tamaño real del archivo para el archivo dado.

  • getHash($hash = 'crc32', $files = null): Este método devuelve un hash del contenido de un archivo transferido dado.

  • getMimeType($files = null): Este método devuelve el tipo mime de un archivo transferido dado.

getFileName() acepta el nombre del elemento como primer parámetro. Si no se da ningún nombre, se devolverán todos los nombres de archivo conocidos en un array. Si el archivo es un archivo múltiple, también obtendrá un array. Si hay un único archivo, se devolverá una cadena.

Por defecto los nombres de archivo se devolverán con la ruta completa. Si solo necesita el nombre de archivo sin la ruta, puede establecer el segundo parámetro, $path, que truncará la ruta del archivo cuando se establezca en FALSE.

Ejemplo 34.3. Obtención del nombre de archivo

$upload = new Zend_File_Transfer();
$upload->receive();

// Returns the file names from all files
$names = $upload->getFileName();

// Returns the file names from the 'foo' form element
$names = $upload->getFileName('foo');

[Note] Nota

Tenga en cuenta que el nombre del archivo puede cambiar después de recibir el archivo, porque todos los filtros se aplicarán una vez recibido el archivo. Por lo tanto, siempre debería llamar a getFileName() después de que los archivos hayan sido recibidos.

getFileSize() devuelve por defecto el tamaño real del archivo en notación SI, lo que significa que obtendrá 2kB en lugar de 2048. Si solo necesita el tamaño en bruto, establezca la opción useByteString en FALSE.

Ejemplo 34.4. Obtención del tamaño de un archivo

$upload = new Zend_File_Transfer();
$upload->receive();

// Returns the sizes from all files as array if more than one file was uploaded
$size = $upload->getFileSize();

// Switches of the SI notation to return plain numbers
$upload->setOptions(array('useByteString' => false));
$size = $upload->getFileSize();

[Note] Tamaño de archivo proporcionado por el cliente

Tenga en cuenta que el tamaño de archivo proporcionado por el cliente no se considera una entrada segura. Por ello, se detectará y devolverá el tamaño real del archivo en lugar del tamaño de archivo enviado por el cliente.

getHash() acepta el nombre de un algoritmo de hash como primer parámetro. Para una lista de los algoritmos conocidos, consulte el método hash_algos de PHP. Si no especifica un algoritmo, se usará por defecto el algoritmo crc32.

Ejemplo 34.5. Obtención del hash de un archivo

$upload = new Zend_File_Transfer();
$upload->receive();

// Returns the hashes from all files as array if more than one file was uploaded
$hash = $upload->getHash('md5');

// Returns the hash for the 'foo' form element
$names = $upload->getHash('crc32', 'foo');

[Note] Valor de retorno

Tenga en cuenta que si el archivo o nombre de formulario dado contiene más de un archivo, el valor devuelto será un array.

getMimeType() devuelve el tipo mime de un archivo. Si se subió más de un archivo, devuelve un array; en caso contrario, una cadena.

Ejemplo 34.6. Obtención del tipo mime de un archivo

$upload = new Zend_File_Transfer();
$upload->receive();

$mime = $upload->getMimeType();

// Returns the mimetype for the 'foo' form element
$names = $upload->getMimeType('foo');

[Note] Tipo mime proporcionado por el cliente

Tenga en cuenta que el tipo mime proporcionado por el cliente no se considera una entrada segura. Por ello, se detectará y devolverá el tipo mime real del archivo en lugar del tipo mime enviado por el cliente.

[Warning] Posible excepción

Tenga en cuenta que este método usa la extensión fileinfo si está disponible. Si esta extensión no se encuentra, usa la extensión mimemagic. Cuando no se encuentra ninguna extensión, lanza una excepción.

[Warning] Datos originales dentro de $_FILES

Por razones de seguridad, los datos originales dentro de $_FILES también se sobrescribirán en cuanto se inicie Zend_File_Transfer. Cuando quiera omitir este comportamiento y conservar los datos originales, simplemente establezca la opción detectInfos en FALSE al inicializar.

Esta opción no tendrá ningún efecto después de haber inicializado Zend_File_Transfer.

34.1.5. Progreso para subidas de archivos

Zend_File_Transfer puede indicarle el estado real de una subida de archivo en curso. Para usar esta funcionalidad necesita bien la extensión APC, que se proporciona con la mayoría de instalaciones de PHP por defecto, o la extensión UploadProgress. Ambas extensiones se detectan y usan automáticamente. Para poder obtener el progreso necesita cumplir algunos requisitos previos.

Primero, necesita tener habilitado APC o UploadProgress. Tenga en cuenta que puede deshabilitar esta funcionalidad de APC en su php.ini.

Segundo, necesita tener los campos ocultos apropiados añadidos en el formulario que envía los archivos. Cuando use Zend_Form_Element_File estos campos ocultos son añadidos automáticamente por Zend_Form.

Cuando se cumplen los dos puntos anteriores, podrá obtener el progreso real de la subida de archivo usando el método getProgress(). En realidad hay 2 formas oficiales de gestionar esto.

34.1.5.1. Uso de un adaptador de barra de progreso

Puede usar el conveniente Zend_ProgressBar para obtener el progreso real y mostrarlo de manera sencilla a su usuario.

Para lograrlo, debe añadir el Zend_ProgressBar_Adapter deseado a getProgress() al llamarlo por primera vez. Para más detalles sobre el adaptador adecuado a usar, consulte el capítulo Adaptadores estándar de Zend_ProgressBar.

Ejemplo 34.7. Uso del adaptador de barra de progreso para recuperar el estado real

$adapter = new Zend_ProgressBar_Adapter_Console();
$upload  = Zend_File_Transfer_Adapter_Http::getProgress($adapter);

$upload = null;
while (!$upload['done']) {
    $upload = Zend_File_Transfer_Adapter_Http:getProgress($upload);
}

La gestión completa la realiza getProgress() por usted en segundo plano.

34.1.5.2. Uso manual de getProgress()

También puede trabajar manualmente con getProgress() sin usar Zend_ProgressBar.

Llame a getProgress() sin configuraciones. Devolverá un array con varias claves. Difieren según la extensión de PHP usada. Pero las siguientes claves se proporcionan independientemente de la extensión:

  • id: El ID de esta subida. Este ID identifica la subida dentro de la extensión. Puede establecerlo al valor de la clave oculta que identificó la subida al llamar inicialmente a getProgress(). Por defecto se establece en progress_key. No debe cambiar el ID posteriormente.

  • total: El tamaño total de los archivos subidos en bytes como entero.

  • current: El tamaño de archivo subido actual en bytes como entero.

  • rate: La velocidad de subida media en bytes por segundo como entero.

  • done: Devuelve TRUE cuando la subida ha finalizado y FALSE en caso contrario.

  • message: El mensaje actual. Ya sea el progreso como texto en la forma 10kB / 200kB, o un mensaje útil en caso de un problema. Los problemas podrían ser que no hay ninguna subida en curso, que hubo un fallo al recuperar los datos para el progreso, o que la subida ha sido cancelada.

  • progress: Esta clave opcional acepta una instancia de Zend_ProgressBar_Adapter o Zend_ProgressBar y permite obtener el estado actual de la subida dentro de una barra de progreso.

  • session: Esta clave opcional acepta el nombre de un espacio de nombres de sesión que se usará dentro de Zend_ProgressBar. Cuando esta clave no se proporciona, por defecto toma el valor de Zend_File_Transfer_Adapter_Http_ProgressBar.

Todas las demás claves devueltas se proporcionan directamente desde las extensiones y no serán comprobadas.

El siguiente ejemplo muestra un posible uso manual:

Ejemplo 34.8. Uso manual del progreso del archivo

$upload  = Zend_File_Transfer_Adapter_Http::getProgress();

while (!$upload['done']) {
    $upload = Zend_File_Transfer_Adapter_Http:getProgress($upload);
    print "\nActual progress:".$upload['message'];
    // do whatever you need
}

[Note] Saber de qué archivo obtener el progreso

El ejemplo anterior funciona cuando el identificador de su subida se establece en 'progress_key'. Cuando use otro identificador dentro de su formulario, debe proporcionar el identificador usado como primer parámetro a getProgress() en la llamada inicial.