PHP:如何重命名使用Zend_Form_Element_File上传的文件?

时间:2009-12-10 20:42:11

标签: php zend-framework file-upload zend-file

形式:

//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);

控制器:

//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();
    }
}

问题:

  1. 当我拨打$form->file->getFileName()时,它会返回完整路径,而不仅仅是文件名。如何仅输出文件名?

    //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. 如何将文件名重命名为我想要的名称?可以使用Rename过滤器完成吗?我已经在表单中设置了目标,所以我想要做的就是更改文件名。也许我不应该在表单中设置目的地?或者这可能无法通过过滤器完成。也许我应该用PHP函数做这个?我该怎么办?

    //Answer: Use the rename filter:
    $form->file->addFilter('Rename', 'new-file-name-goes-here.txt');
    
  3. 最终解决方案:

    这就是我最终做的事情:

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

7 个答案:

答案 0 :(得分:8)

使用rename filter

答案 1 :(得分:6)

要回答问题1,要从完整路径获取文件名,您可以使用basenamepathinfo

例如(来自文档的复制粘贴)

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

或者:

$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


要重命名/移动文件,我认为rename可以解决问题,即使它不是“Zend Framework解决方案”。

如果文件尚未被ZF移动并且仍在临时目录中,则应使用move_uploaded_file - 但在使用setDestination时,我认为该文件已不在sytem的临时目录。

答案 2 :(得分:5)

伙计们,这是一个在上传文件后对文件使用the rename filter的表单的简单示例。还有更多的选择,是的,你需要考虑现有的文件,但为了让你开始,你走了。

当文件通过下面的表单上传时,它将重命名为“ 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();
}

答案 3 :(得分:4)

在上传之前轻松修复Zend重命名

我在这里解决的问题在这里有更详细的解释:http://www.thomasweidner.com/flatpress/2009/04/17/recieving-files-with-zend_form_element_file/

在上传之前我无法重命名该文件,并找到了我的方案的解决方案。在某些时候,Zend认为让文件元素的getValue()方法为您上传文件很聪明。幸运的是,他们添加了一个禁用此功能的选项。

解决方案:如果您在文件元素上调用getValue(),或者在表单上调用getValues(),并且您希望在上传之前修改名称,则必须设置setValueDisabled(true)在Zend_Form_Element_File上。

Fyi:我不认为这是优化的,我只是声称它适合我

创建表单元素 magic inside

$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');

在上传前重命名(在preUpload($ form)内)

$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()
}

帮助方法

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

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

答案 4 :(得分:2)

由于一些原因,Zend很难做到这一点。

  1. 如果在将文件移动到上传目标后重命名该文件,则可能会覆盖您不想重写的文件。
  2. 例如,假设您有一个名为/ path / to / my / pics的目标目录。如果两个用户同时上传了一张名为“me.png”的图片,那么他们可能会互相覆盖。这是因为在将文件移动到/ path / to / my / pics之后应用重命名过滤器。因此,在新文件上传覆盖之前,它可能不会被重命名。

    1. 如果您使用Zend的重命名过滤器,则无法保留原始文件扩展名。
    2. 我这样做是为了做到以下几点, 1.扩展http传输适配器以将重命名过滤器传递给原始文件名。普通的http传输适配器传入tmp目录中的临时名称,并且没有文件扩展名。

      1. 扩展重命名过滤器,以便您可以指定是否应保留原始文件扩展名。
      2. 之后,您必须将前缀添加到您正在使用的表单中,以便表单可以找到您的适配器,以便您的适配器可以找到您已经创建的新重命名过滤器。

        我这样做的原因是因为我的目的地目录中每张用户名为“user1.jpg”或“user2.png”的每个用户都会有一张图片。我想在移动它的同时重命名该文件,以便它不会覆盖我想保留的目录中的任何其他文件。

        这是我用过的代码。

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

        这是适配器,现在用于过滤器。

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

        然后,您必须将前缀路径添加到您上传文件的文件元素中。

        
        
        $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 );
        
        
        

        当您将过滤器添加到文件元素时,您必须按照以下方式执行此操作

        
        $fileElement->addFilter(
                                'File_Rename',
                                array(
                                    'target' => $this->_getPictureDestination() . DIRECTORY_SEPARATOR . "user$userId",
                                    'overwrite' => true,
                                    'keepExtension' => true
                                )
                    )
        
        
        

        现在,当文件移动到新目录时,它们将具有原始文件扩展名,并且它们将具有您在将过滤器添加到文件元素时指定的新名称。

        如果这很难理解,请告诉我。我花了一段时间才弄清楚Zend发生了什么事情,所以如果它对任何人都有帮助,可以自由使用这段代码。

答案 5 :(得分:1)

//对于Zend Framework ::重命名已上载的文件

 $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);

答案 6 :(得分:0)

您可以使用重命名过滤器。如果您想在上传过程中重命名文件名,可能对您有帮助。

首先我们需要重命名函数或从文件名中删除不需要的字符,例如使用它。

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

之后,您可以使用上述功能进行重命名。

$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())));

这很容易。不是吗?