PHP: How to rename a file uploaded with Zend_Form_Element_File?

Viewed 26223

Form:

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

Controller:

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

Questions:

  1. When I call $form->file->getFileName() it returns the full path, not just the file name. How can I output just the name of the file?

    //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. How can I rename the filename to something I want? Can this be done with the Rename filter? I'm already setting the destination in the form, so all I want to do is change the filename. Maybe I shouldn't be setting the destination in the form? Or maybe this can't be done with a filter. Maybe I should be doing this with a PHP function? What should I do?

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

Final Solution:

This is what I ended up doing:

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 Answers

To answer question 1, to get a filename from a full path, you can use basename, or pathinfo.

For example (copy-paste from the doc) :

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

Or :

$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


To rename / move the file, I suppose rename would do the trick, even if it's quite not "Zend Framework solution".

If the file has not been moved by ZF and is still in the temporary directory, you should use move_uploaded_file -- but as you are using setDestination, I suppose the file is no longer in the sytem's temporary directory.

Easy fix to get Zend to rename before uploading

The problem I address here is explained in more detail here: http://www.thomasweidner.com/flatpress/2009/04/17/recieving-files-with-zend_form_element_file/

I was having trouble getting the file to rename before uploading and found the solution for my scenario. At some point Zend thought it clever to have the getValue() method of the file element upload the file for you. Fortunately they added an option to disable this feature.

Solution: If you are calling getValue() on the file element, or getValues() on the form, and you want to modify the name before it uploads you have to set setValueDisabled(true) on your Zend_Form_Element_File.

Fyi: I don't claim this to be optimized, I just claim it to work for me

Creating the form element (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');

Rename before uploading (inside 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()
}

Helper methods

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

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

// For Zend Framework :: Rename Uploaded File

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