web-dev-qa-db-fra.com

PHP: Comment renommer un fichier envoyé avec Zend_Form_Element_File?

Forme:

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

Manette:

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

Des questions:

  1. Lorsque j'appelle $form->file->getFileName(), le chemin complet est renvoyé, pas seulement le nom du fichier. Comment puis-je sortir juste le nom du fichier?

    //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. Comment puis-je renommer le nom de fichier en quelque chose que je veux? Cela peut-il être fait avec le filtre Rename? Je suis déjà en train de définir la destination dans le formulaire, donc tout ce que je veux, c'est changer le nom du fichier. Peut-être que je ne devrais pas définir la destination dans le formulaire? Ou peut-être que cela ne peut pas être fait avec un filtre. Peut-être devrais-je faire cela avec une fonction PHP? Que devrais-je faire?

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

Solution finale:

C'est ce que j'ai fini par faire:

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

Pour répondre à la question 1, pour obtenir un nom de fichier à partir d’un chemin complet, vous pouvez utiliser basename ou pathinfo .

Par exemple (copier-coller depuis la doc) :

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

Ou :

$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


Pour renommer/déplacer le fichier, je suppose que rename ferait l'affaire, même si ce n'est en aucun cas une "solution Zend Framework".

Si le fichier n'a pas été déplacé par ZF et se trouve toujours dans le répertoire temporaire, vous devez utiliser move_uploaded_file -, mais comme vous utilisez setDestination, je suppose que le fichier ne se trouve plus dans le répertoire temporaire du système.

6
Pascal MARTIN

Utilisez le filtre renommer .

8
Elzo Valugi

Mes amis, voici un exemple simple de formulaire qui utilise le filtre de changement de nom sur un fichier après son téléchargement. Il existe de nombreuses autres options et, oui, vous devez prendre en compte les fichiers existants, mais pour commencer, vous y êtes.

Une fois le fichier chargé via le formulaire ci-dessous, il sera renommé ' 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();
}
5
Matt Setter

Solution facile pour que Zend soit renommé avant de télécharger

Le problème que je traite ici est expliqué plus en détail ici: http://www.thomasweidner.com/flatpress/2009/04/17/recieving-files-with-zend_form_element_file/

J'avais du mal à renommer le fichier avant de télécharger et de trouver la solution à mon scénario. À un moment donné, Zend a trouvé astucieux que la méthode getValue () de l'élément file télécharge le fichier pour vous. Heureusement, ils ont ajouté une option pour désactiver cette fonctionnalité.

Solution: Si vous appelez getValue () sur l'élément file ou getValues ​​() sur le formulaire et que vous souhaitez modifier le nom avant son téléchargement, vous devez définir setValueDisabled (true) sur votre Zend_Form_Element_File.

_ {Fyi: Je ne prétends pas que cela soit optimisé, je prétends juste que ça marche pour moi} _

Création de l'élément de formulaire (magie à l'intérieur _)

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

Renommer avant de télécharger (dans 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()
}

Méthodes auxiliaires

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

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

C'est difficile à faire avec Zend pour plusieurs raisons. 

  1. Si vous renommez le fichier après l'avoir déplacé vers la destination de téléchargement, il se peut que vous ayez écrasé un fichier que vous ne vouliez pas réécrire. 

Par exemple, supposons que vous ayez un répertoire de destination appelé/path/to/my/pics. Si deux utilisateurs téléchargent simultanément une image intitulée «me.png», ils risquent alors de se remplacer l'un l'autre. Cela est dû au fait que le filtre de changement de nom est appliqué APRÈS que le fichier soit déplacé vers/chemin/vers/mes/images. Ainsi, il se peut qu'il ne soit pas renommé avant d'être remplacé par un nouveau téléchargement de fichier.

  1. Si vous utilisez le filtre de changement de nom de Zend, vous ne pouvez pas conserver l'extension de fichier d'origine.

Je l’ai fait comme suit: 1. Étendez l'adaptateur de transfert http pour passer le filtre de renommage au nom de fichier d'origine. L'adaptateur de transfert http normal transmet le nom temporaire dans le répertoire tmp et n'a pas l'extension de fichier.

  1. Étendez le filtre de changement de nom afin de pouvoir spécifier s'il doit ou non conserver l'extension de fichier d'origine.

Ensuite, vous devrez ajouter le préfixe au formulaire que vous utilisez pour que celui-ci trouve votre adaptateur et que celui-ci trouve le nouveau filtre Renommer que vous avez créé.

La raison pour laquelle je l'ai fait de cette façon est parce que mon répertoire de destination allait contenir une image pour chaque utilisateur pour lequel chaque image était nommée 'user1.jpg' ou 'user2.png'. Je voulais renommer le fichier en même temps que je l'avais déplacé pour qu'il ne remplace aucun autre fichier du répertoire que je voulais conserver. 

Voici le code que j'ai utilisé. 


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

C'est l'adaptateur, maintenant pour le filtre.


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

}

Vous devrez ensuite ajouter le chemin du préfixe à l'élément de fichier que vous avez créé pour télécharger le fichier.



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

Lorsque vous ajoutez le filtre à l'élément de fichier, vous devrez le faire de la manière suivante


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

Désormais, lorsque les fichiers seront déplacés vers le nouveau répertoire, ils auront l'extension de fichier d'origine et le nouveau nom que vous avez spécifié lors de l'ajout du filtre à l'élément de fichier.

Si cela était difficile à comprendre s'il vous plaît faites le moi savoir. Il m'a fallu un certain temps pour comprendre ce qui se passait dans Zend, alors si cela peut aider quelqu'un, utilisez ce code librement.

2
Jerry Saravia

// Pour Zend Framework :: Renommer le fichier téléchargé

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

Vous pouvez utiliser le filtre Renommer. Si vous souhaitez renommer votre nom de fichier lors du téléchargement, cela vous aidera peut-être.

Nous devons d’abord une fonction renommer ou supprimer les caractères indésirables de votre nom de fichier pour pouvoir l’utiliser par exemple.

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

Après cela, vous pouvez utiliser la fonction ci-dessus pour renommer.

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

C'est facile. N'est-ce pas?

0
aramisz