繁体   English   中英

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

[英]PHP: How to rename a file uploaded with Zend_Form_Element_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'); 

最终解决方案

这就是我最终做的事情:

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

使用重命名过滤器

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

例如(从doc复制粘贴)

$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 ,我认为该文件不再位于系统的临时目录中。

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

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

轻松修复以在上传之前让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)。

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

创建表单元素魔术内部

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

由于一些原因,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发生了什么事情,所以如果有人帮助,请自由使用这段代码。

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

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

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

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

这很容易。 是不是?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM