validar subir subida renombrar otro nombre move_uploaded_file imagen guardar ejemplo con cambiar archivos archivo php zend-framework file-upload zend-file

subida - subir y renombrar archivos con php move_uploaded_file



PHP: ¿cómo cambiar el nombre de un archivo cargado con Zend_Form_Element_File? (7)

Formar:

//excerpt $file = new Zend_Form_Element_File(''file''); $file->setLabel(''File to upload:'') ->setRequired(true) ->addValidator(''NotEmpty'') ->addValidator(''Count'', false, 1) ->setDestination(APPLICATION_UPLOADS_DIR); $this->addElement($file);

Controlador:

//excerpt if ($form->isValid($request->getPost()) { $newFilename = ''foobar.txt''; //how should I rename the file? //When should I rename the file? Before or after receiving? try { $form->file->receive(); echo ''filename: ''. $form->file->getFileName(); } }

Preguntas:

  1. Cuando llamo $form->file->getFileName() devuelve la ruta completa, no solo el nombre del archivo. ¿Cómo puedo generar solo el nombre del archivo?

    //Answer: First, get an array of the parts of the filename: $pathparts = pathinfo($form->file->getFileName()); //then get the part that you want to use $originalFilename = $pathparts[''basename''];

  2. ¿Cómo puedo cambiar el nombre del nombre de archivo a algo que quiero? ¿Se puede hacer esto con el filtro Rename ? Ya estoy configurando el destino en el formulario, así que todo lo que quiero hacer es cambiar el nombre del archivo. Tal vez no debería establecer el destino en el formulario? O tal vez esto no se puede hacer con un filtro. Tal vez debería estar haciendo esto con una función de PHP? ¿Que debería hacer?

    //Answer: Use the rename filter: $form->file->addFilter(''Rename'', ''new-file-name-goes-here.txt'');

Solución final:

Esto es lo que terminé haciendo:

public function foobarAction() { //...etc... if (!$form->isValid($request->getPost())) { $this->view->form = $form; return; } //the following will rename the file (I''m setting the upload dir in the form) $originalFilename = pathinfo($form->file->getFileName()); $newFilename = ''file-'' . uniqid() . ''.'' . $originalFilename[''extension'']; $form->file->addFilter(''Rename'', $newFilename); try { $form->file->receive(); //upload complete! $file = new Default_Model_File(); $file->setDisplayFilename($originalFilename[''basename'']) ->setActualFilename($newFilename) ->setMimeType($form->file->getMimeType()) ->setDescription($form->description->getValue()); $file->save(); } catch (Exception $e) { //error: file couldn''t be received, or saved (one of the two) } }


Amigos, aquí hay un ejemplo simple de un formulario que usa el filtro de cambio de nombre en un archivo después de que se ha cargado. Hay muchas más opciones y sí, debe tener en cuenta los archivos existentes, pero para empezar, aquí tiene.

Cuando el archivo se cargue a través del siguiente formulario, se cambiará a '' config.ini ''.

$form = new Zend_Form; $form->setAction(''/default/index/file-upload'') ->setMethod(''post''); $uploadFile = new Zend_Form_Element_File(''uploadfile''); $uploadFile->addFilter(new Zend_Filter_File_Rename( array(''target'' => ''config.ini'')) ) ->setRequired(true) ->setLabel(''Upload file:''); $form->addElement($uploadFile); $form->addElement(new Zend_Form_Element_Submit(''submit'')); if ($form->isValid($_POST)) { $values = $form->getValues(); }


Esto es difícil de hacer con Zend por algunas razones.

  1. Si cambia el nombre del archivo después de que se haya movido al destino de carga, es posible que haya sobrescrito un archivo que no desea volver a escribir.

Por ejemplo, supongamos que tiene un directorio de destino llamado / ruta / a / mi / imágenes. Si dos usuarios, al mismo tiempo, suben una imagen llamada ''me.png'', es posible que se anulen entre sí. Esto se debe a que el filtro de cambio de nombre se aplica DESPUÉS de que el archivo se mueva a / ruta / a / mi / imágenes. Por lo tanto, es posible que no se renombre antes de que se sobrescriba con una nueva carga de archivo.

  1. Si usa el filtro de cambio de nombre de Zend, entonces no puede mantener la extensión de los archivos originales.

La forma en que lo hice fue hacer lo siguiente: 1. Extender el adaptador de transferencia HTTP para pasar el filtro de cambio de nombre al nombre del archivo original. El adaptador de transferencia http normal transmite el nombre temporal en el directorio tmp y no tiene la extensión de archivo.

  1. Extienda el filtro de cambio de nombre para que pueda especificar si debe mantener o no la extensión original del archivo.

Después, tendrá que agregar el prefijo al formulario que está utilizando para que el formulario pueda encontrar su adaptador y, por lo tanto, su adaptador pueda encontrar el nuevo filtro Cambiar nombre que haya creado.

La razón por la que lo hice de esta manera es porque mi directorio de destino iba a tener una imagen para cada usuario donde cada imagen se llamaba ''usuario1.jpg'' o ''usuario2.png''. Quería cambiar el nombre del archivo al mismo tiempo que lo moví para que no anulara ningún otro archivo en el directorio que deseaba conservar.

Aquí está el código que he usado.

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; } }

Ese 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; } }

Luego deberá agregar la ruta del prefijo al elemento de archivo que ha creado para cargar 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 agregue el filtro al elemento de archivo, tendrá 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 muevan al nuevo directorio, tendrán la extensión original y tendrán el nuevo nombre que usted especificó cuando agregó el filtro al elemento del archivo.

Si esto fue difícil de entender, por favor avíseme. Me tomó un tiempo averiguar qué estaba pasando en Zend para hacer esto, así que si ayuda a alguien, use este código libremente.


Para responder a la pregunta 1, para obtener un nombre de archivo de una ruta completa, puede usar basename o pathinfo .

Por ejemplo (copiar y pegar desde el documento) :

$path = "/home/httpd/html/index.php"; $file = basename($path); // $file is set to "index.php"

O bien:

$path_parts = pathinfo(''/www/htdocs/index.html''); echo $path_parts[''dirname''], "/n"; echo $path_parts[''basename''], "/n"; echo $path_parts[''extension''], "/n"; echo $path_parts[''filename''], "/n"; // since PHP 5.2.0


Para renombrar / mover el archivo, supongo que rename haría el truco, incluso si no se trata de la "solución Zend Framework".

Si el archivo no ha sido movido por ZF y aún está en el directorio temporal, debe usar move_uploaded_file , pero como está usando setDestination , supongo que el archivo ya no está en el directorio temporal del sistema.


Puede usar Cambiar el nombre del filtro. Si desea cambiar el nombre de su nombre de archivo durante la carga, tal vez lo ayude.

Primero necesitamos una función para cambiar el nombre o eliminar caracteres no deseados de su nombre de archivo, por ejemplo, usar esto.

public function simple_fileformat($str) { $str = preg_replace("{[^A-Za-z0-9_]/.}", "", $str); $str = str_replace(" ", "_", $str); return $str; }

Después de eso, puede usar la función anterior para cambiar el nombre.

$filename = new Zend_Form_Element_File("filename"); $filename->setLabel("filename"); $filename->setRequired(true); $filename->setDestination($doc_path); $filename->addFilter("rename", $doc_path . DIRECTORY_SEPARATOR . $this->simple_fileformat(basename($filename->getFileName())));

Eso es fácil. ¿No?



// Para Zend Framework :: Cambiar el nombre del archivo cargado

$renameFile = ''newName.jpg''; $fullFilePath = ''/images/''.$renameFile; // Rename uploaded file using Zend Framework $filterFileRename = new Zend_Filter_File_Rename(array(''target'' => $fullFilePath, ''overwrite'' => true)); $filterFileRename -> filter($name);


Una solución fácil para que Zend cambie el nombre antes de subirlo

El problema que abordo aquí se explica con más detalle aquí: http://www.thomasweidner.com/flatpress/2009/04/17/recieving-files-with-zend_form_element_file/

Estaba teniendo problemas para cambiar el nombre del archivo antes de cargarlo y encontré la solución para mi escenario. En algún momento Zend pensó que era inteligente tener el método getValue () del elemento de archivo para cargar el archivo por usted. Afortunadamente, agregaron una opción para desactivar esta función.

Solución: si está llamando a getValue () en el elemento de archivo, o getValues ​​() en el formulario, y desea modificar el nombre antes de que se cargue, debe establecer setValueDisabled (true) en su Zend_Form_Element_File.

Fyi: No pretendo que esto esté optimizado, solo digo que funciona para mí

Creando el elemento de forma ( magia adentro )

$uploadConfig = Zend_Registry::get(''upload''); $fileuploader = new Zend_Form_Element_File(''ugc_fileupload''); $fileuploader->setRequired(true); $fileuploader->setLabel(''*Upload File:''); $fileuploader->addValidator(''Count'', false, 1); // ensure only 1 file $fileuploader->setValueDisabled(true); // ***THIS IS THE MAGIC*** $fileuploader->addValidator(''Size'', false, $uploadConfig[''videomax'']); $fileuploader->addValidator(''Extension'', false, ''mov, avi, wmv, mp4''); $this->addElement($fileuploader, ''ugc_fileupload'');

Renombrar antes de cargar (dentro de preUpload ($ formulario))

$uploadCfg = Zend_Registry::get(''upload''); // Get the parts of the name // Call to getValue() here was uploading the file before telling it not to! $atiFile = $form->ugc_fileupload->getValue(); $fileExt = $this->getFileExtension($atiFile); $nameBase = $this->getFileName($atiFile, $fileExt); $fullName = $atiFile; $fullPath = $uploadCfg[''tmpdir''] . $fullName; // Keep checking until the filename doesn''t exist $numToAdd = 0; while(file_exists($fullPath)) { $fullName = $nameBase . $numToAdd . $fileExt; $fullPath = $uploadCfg[''tmpdir''] . $fullName; $numToAdd++; } $upload = new Zend_File_Transfer_Adapter_Http(); // or $upload = $form->ugc_fileupload->getTransferAdapter(); // both work, I''m not sure if one is better than the other... //Now that the file has not already been uploaded renaming works $upload->addFilter(new Zend_Filter_File_Rename(array( ''target'' => $fullPath, ''overwrite'' => false) )); try { $upload->receive(); } catch (Zend_File_Transfer_Exception $e) { //$e->getMessage() }

Métodos de ayuda

public function getFileName($path, $ext) { return $bname = basename($path, $ext); } public function getFileExtension($path) { return $ext = strrchr($path, ''.''); }