Esto es difícil de hacer con Zend para un par de razones.
- Si cambia el nombre del archivo después de que se haya movido para el destino de la carga, a continuación, podría haber sobrescribir un archivo que no se quería volver a escribir.
Por ejemplo, supongamos que tenemos un directorio de destino, el nombre /ruta/a/mi/pics. Si dos usuarios, al mismo tiempo, subir una imagen llamada 'mí.png', que podría anular el uno al otro. Esto es debido a que el cambio de nombre se aplica el filtro DESPUÉS de que el archivo se mueve a la /ruta/a/mi/pics. Por lo tanto, no se podría haber cambiado el nombre antes de que se sobrescribe con un nuevo archivo de carga.
- Si el uso de Zend cambiar el nombre de filtro, a continuación, usted no puede mantener los archivos originales de extensión.
La manera en que lo hice fue hacer lo siguiente,
1. Extender el http transferencia adaptador para aprobar el cambio de nombre de filtro el nombre de archivo original. La normal http transferencia adaptador pasa en el nombre temporal en el directorio tmp y no tienen la extensión de archivo.
- Extender el cambiar el nombre de filtro de modo que usted puede especificar si se debe o no mantener la extensión de archivo original.
Después de esto, usted tendrá que agregar el prefijo a la forma que usted está utilizando para que el formulario se puede encontrar el adaptador y así el adaptador se puede encontrar el nuevo cambiar el nombre del filtro que has hecho.
La razón por la que hice de esta manera es porque mi directorio de destino que iba a tener una foto en el que para cada usuario, donde cada pic fue nombrado 'user1.jpg' o 'usuario2.png'. Yo quería cambiar el nombre del archivo al mismo tiempo que me movía por lo que no reemplazan cualquier otros archivos en el directorio que quería mantener.
Aquí está el código que he utilizado.
class My_File_Transfer_Adapter_Http
extends Zend_File_Transfer_Adapter_Http
{
/**
* Receive the file from the client (Upload)
* This differs from the Zend adapter in that
* the adapter passes in the files actual
* name to the rename filter so that when
* it is renamed, the renamer can use the extension
* of the file and keep it or change it.
*
* @param string|array $files (Optional) Files to receive
* @return bool
*/
public function receive($files = null)
{
if (!$this->isValid($files)) {
return false;
}
$check = $this->_getFiles($files);
foreach ($check as $file => $content) {
if (!$content['received']) {
$directory = '';
$destination = $this->getDestination($file);
if ($destination !== null) {
$directory = $destination . DIRECTORY_SEPARATOR;
}
/******************************************/
// The original transfer adapter
// passes content['tmp_name']
// but we'll pass in content['name'] instead
// to have access to the extension
/******************************************/
$filename = $directory . $content['name'];
$rename = $this->getFilter('File_Rename');
if ($rename !== null) {
$tmp = $rename->getNewName($content['name']);
if ($tmp != $content['name']) {
$filename = $tmp;
}
if (dirname($filename) == '.') {
$filename = $directory . $filename;
}
$key = array_search(get_class($rename), $this->_files[$file]['filters']);
unset($this->_files[$file]['filters'][$key]);
}
// Should never return false when it's tested by the upload validator
if (!move_uploaded_file($content['tmp_name'], $filename)) {
if ($content['options']['ignoreNoFile']) {
$this->_files[$file]['received'] = true;
$this->_files[$file]['filtered'] = true;
continue;
}
$this->_files[$file]['received'] = false;
return false;
}
if ($rename !== null) {
$this->_files[$file]['destination'] = dirname($filename);
$this->_files[$file]['name'] = basename($filename);
}
$this->_files[$file]['tmp_name'] = $filename;
$this->_files[$file]['received'] = true;
}
if (!$content['filtered']) {
if (!$this->_filter($file)) {
$this->_files[$file]['filtered'] = false;
return false;
}
$this->_files[$file]['filtered'] = true;
}
}
return true;
}
}
Que es el adaptador, ahora para el filtro.
class My_Filter_File_Rename
extends Zend_Filter_File_Rename
{
/**
* Internal array of array(source, target, overwrite)
*/
protected $_files = array( );
/**
* Class constructor
*
* Options argument may be either a string, a Zend_Config object, or an array.
* If an array or Zend_Config object, it accepts the following keys:
* 'source' => Source filename or directory which will be renamed
* 'target' => Target filename or directory, the new name of the sourcefile
* 'overwrite' => Shall existing files be overwritten ?
* 'keepExtension' => Should the files original extension be kept
*
* @param string|array $options Target file or directory to be renamed
* @param string $target Source filename or directory (deprecated)
* @param bool $overwrite Should existing files be overwritten (deprecated)
* @return void
*/
public function __construct( $options )
{
if( $options instanceof Zend_Config )
{
$options = $options->toArray();
}
elseif( is_string( $options ) )
{
$options = array( 'target' => $options );
}
elseif( !is_array( $options ) )
{
require_once 'Zend/Filter/Exception.php';
throw new Zend_Filter_Exception( 'Invalid options argument provided to filter' );
}
if( 1 setFile( $options );
}
/**
* Returns the files to rename and their new name and location
*
* @return array
*/
public function getFile()
{
return $this->_files;
}
/**
* Sets a new file or directory as target, deleting existing ones
*
* Array accepts the following keys:
* 'source' => Source filename or directory which will be renamed
* 'target' => Target filename or directory, the new name of the sourcefile
* 'overwrite' => Shall existing files be overwritten ?
* 'keepExtension' => Should the files original extension be kept
*
* @param string|array $options Old file or directory to be rewritten
* @return Zend_Filter_File_Rename
*/
public function setFile( $options )
{
$this->_files = array( );
$this->addFile( $options );
return $this;
}
/**
* Adds a new file or directory as target to the existing ones
*
* Array accepts the following keys:
* 'source' => Source filename or directory which will be renamed
* 'target' => Target filename or directory, the new name of the sourcefile
* 'overwrite' => Shall existing files be overwritten ?
* 'keepExtension' => Should the files original extension be kept
*
* @param string|array $options Old file or directory to be rewritten
* @return Zend_Filter_File_Rename
*/
public function addFile( $options )
{
if( is_string( $options ) )
{
$options = array( 'target' => $options );
}
elseif( !is_array( $options ) )
{
require_once 'Zend/Filter/Exception.php';
throw new Zend_Filter_Exception( 'Invalid options to rename filter provided' );
}
$this->_convertOptions( $options );
return $this;
}
/**
* Returns only the new filename without moving it
* But existing files will be erased when the overwrite option is true
*
* @param string $value Full path of file to change
* @param boolean $source Return internal informations
* @return string The new filename which has been set
*/
public function getNewName( $value,
$source = false )
{
$file = $this->_getFileName( $value );
if( $file[ 'source' ] == $file[ 'target' ] )
{
return $value;
}
if( !file_exists( $file[ 'source' ] ) && !$file['keepExtension'] )
{
return $value;
}
if( ($file[ 'overwrite' ] == true) && (file_exists( $file[ 'target' ] )) )
{
unlink( $file[ 'target' ] );
}
if( file_exists( $file[ 'target' ] ) )
{
require_once 'Zend/Filter/Exception.php';
throw new Zend_Filter_Exception( sprintf( "File '%s' could not be renamed. It already exists.",
$value ) );
}
if( $source )
{
return $file;
}
return $file[ 'target' ];
}
/**
* Defined by Zend_Filter_Interface
*
* Renames the file $value to the new name set before
* Returns the file $value, removing all but digit characters
*
* @param string $value Full path of file to change
* @throws Zend_Filter_Exception
* @return string The new filename which has been set, or false when there were errors
*/
public function filter( $value )
{
$file = $this->getNewName( $value, true );
if( is_string( $file ) )
{
return $file;
}
$result = rename( $file[ 'source' ], $file[ 'target' ] );
if( $result === true )
{
return $file[ 'target' ];
}
require_once 'Zend/Filter/Exception.php';
throw new Zend_Filter_Exception( sprintf( "File '%s' could not be renamed. An error occured while processing the file.",
$value ) );
}
/**
* Internal method for creating the file array
* Supports single and nested arrays
*
* @param array $options
* @return array
*/
protected function _convertOptions( $options )
{
$files = array( );
foreach( $options as $key => $value )
{
if( is_array( $value ) )
{
$this->_convertOptions( $value );
continue;
}
switch( $key )
{
case "source":
$files[ 'source' ] = ( string ) $value;
break;
case 'target' :
$files[ 'target' ] = ( string ) $value;
break;
case 'overwrite' :
$files[ 'overwrite' ] = ( boolean ) $value;
break;
case 'keepExtension':
$files[ 'keepExtension' ] = ( boolean ) $value;
break;
default:
break;
}
}
if( empty( $files ) )
{
return $this;
}
if( empty( $files[ 'source' ] ) )
{
$files[ 'source' ] = '*';
}
if( empty( $files[ 'target' ] ) )
{
$files[ 'target' ] = '*';
}
if( empty( $files[ 'overwrite' ] ) )
{
$files[ 'overwrite' ] = false;
}
if( empty( $files[ 'keepExtension' ] ) )
{
$files[ 'keepExtension' ] = true;
}
$found = false;
foreach( $this->_files as $key => $value )
{
if( $value[ 'source' ] == $files[ 'source' ] )
{
$this->_files[ $key ] = $files;
$found = true;
}
}
if( !$found )
{
$count = count( $this->_files );
$this->_files[ $count ] = $files;
}
return $this;
}
/**
* Internal method to resolve the requested source
* and return all other related parameters
*
* @param string $file Filename to get the informations for
* @return array
*/
protected function _getFileName( $file )
{
$rename = array( );
foreach( $this->_files as $value )
{
if( $value[ 'source' ] == '*' )
{
if( !isset( $rename[ 'source' ] ) )
{
$rename = $value;
$rename[ 'source' ] = $file;
}
}
if( $value[ 'source' ] == $file )
{
$rename = $value;
}
}
if( !isset( $rename[ 'source' ] ) )
{
return $file;
}
if( !isset( $rename[ 'target' ] ) or ($rename[ 'target' ] == '*') )
{
$rename[ 'target' ] = $rename[ 'source' ];
}
if( is_dir( $rename[ 'target' ] ) )
{
$name = basename( $rename[ 'source' ] );
$last = $rename[ 'target' ][ strlen( $rename[ 'target' ] ) - 1 ];
if( ($last != '/') and ($last != '\\') )
{
$rename[ 'target' ] .= DIRECTORY_SEPARATOR;
}
$rename[ 'target' ] .= $name;
}
if( !is_dir( $rename['target'] ) || $rename[ 'keepExtension' ] )
{
$name = basename( $rename[ 'source' ] );
$parts = explode( '.', $name );
$extension = $parts[count( $parts ) - 1];
$rename[ 'target' ] .= '.' . $extension;
}
return $rename;
}
}
Será el momento de añadir el prefijo de la ruta de acceso al archivo de elemento que has hecho para subir el archivo.
$fileElement->addPrefixPath('My_File_Transfer_Adapter', 'My/File/Transfer/Adapter', Zend_Form_Element_File::TRANSFER_ADAPTER );
$fileElement->addPrefixPath( 'My_Filter', 'My/Filter', Zend_Form_Element_File::FILTER );
Cuando se agrega el filtro para el elemento de archivo tendrás que hacerlo de la siguiente manera
$fileElement->addFilter(
'File_Rename',
array(
'target' => $this->_getPictureDestination() . DIRECTORY_SEPARATOR . "user$userId",
'overwrite' => true,
'keepExtension' => true
)
)
Ahora, cuando los archivos se trasladó al nuevo directorio que van a tener los archivos originales de extensión y van a tener el nuevo nombre que especificó cuando se agrega el filtro para el elemento de archivo.
Si esto era difícil de entender, por favor hágamelo saber. Me tomó un tiempo para averiguar lo que estaba pasando en Zend para hacer esto, así que, si ayuda a alguien, utilice este código libremente.