28

形式:

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

最终解决方案:

这就是我最终做的事情:

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

7 回答 7

8

使用重命名过滤器

于 2009-12-10T20:46:46.620 回答
6

要回答问题 1,要从完整路径中获取文件名,您可以使用basename, 或pathinfo.

例如(从文档复制粘贴)

$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 框架解决方案”。

如果文件没有被 ZF 移动并且仍然在临时目录中,你应该使用move_uploaded_file-- 但是当你使用setDestination时,我想文件不再在系统的临时目录中。

于 2009-12-10T20:44:12.087 回答
5

伙计们,这是一个简单的表单示例,它在文件上传后对文件使用重命名过滤器。还有更多选项,是的,您需要考虑现有文件,但为了让您开始,就在这里。

当文件通过下面的表格上传时,它将被重命名为' 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();
}
于 2011-11-25T09:55:31.380 回答
4

在上传之前让 Zend 重命名的简单修复

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

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

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

仅供参考:我没有声称这是优化的,我只是声称它对我有用

创建表单元素里面的魔法

$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, '.');
}
于 2012-04-12T02:41:44.583 回答
2

Zend 很难做到这一点,原因有几个。

  1. 如果您在将文件移动到上传目的地后重命名该文件,则它可能覆盖了您不想重写的文件。

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

  1. 如果您使用 Zend 的重命名过滤器,那么您将无法保留原始文件扩展名。

我这样做的方法是执行以下操作,1.扩展http传输适配器以通过重命名过滤器原始文件名。普通的http传输适配器传入tmp目录下的临时名称,没有文件扩展名。

  1. 扩展重命名过滤器,以便您可以指定它是否应保留原始文件扩展名。

之后,您必须将前缀添加到您正在使用的表单中,以便表单可以找到您的适配器,并且您的适配器可以找到您创建的新重命名过滤器。

我这样做的原因是因为我的目标目录将为每个用户提供一张图片,其中每张图片都被命名为“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 中发生了什么,所以如果它对任何人有帮助,请自由使用此代码。

于 2011-09-10T16:28:34.983 回答
1

// 对于 Zend 框架 :: 重命名上传的文件

 $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);
于 2009-12-10T20:49:47.707 回答
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())));

这很容易。是不是?

于 2014-06-21T14:16:52.373 回答