Friday
17
April
2009

Recieving files with Zend_Form_Element_File

How to receive a file from Zend_Form_Element_File is often a difficult question.
When you have problems you should read below to get an idea of the handling and to prevent possible problems:

Let’s expect our form has a file element like this one:

$element = new Zend_Form_Element_File('file');
$element->setDestination('/MyDir');

In past, before ZF 1.8, when you wanted to get the uploaded file you had to call receive() afterwards like this…

if ($form->isValid($this->getPost())) {
    if (!$element->file->receive()) {
        print_r($element->file->getMessages());
    }
}

Now many people said, and I think they were right, that it would be a great idea to get the file when calling getValues(). So we added this new feature for ZF 1.8.

This means that that with ZF 1.8 this call is enough:

$values = $form->getValues();

Your file is already transferred… no need to call received afterwards.

But sometime it is wished to call received manually. You could, for example, wish to add a own filter based on a value which you get from your form. So calling getValues() now would mean that you can not add a filter afterwards… as the file is already transferred.

But also for this usecase a solution has been added. You can set a flag to the file element which prevents that the file itself will be received when you call getValues().

Take a look at the following file element:

$element = new Zend_Form_Element_File('file');
$element->setDestination('/MyDir')
        ->setValueDisabled(true);

Note the added call of setValueDiabled(). It tells the file element that it should not receive the file when you call getValues().

Now you can call getValues() and the file will not be received in the background. But this means, of course, that you have to call receive() manually. Otherwise your file will not be available after the script has been finished.

$values = $form->getValues();
	
if ($form->isValid($this->getPost())) {
    $element->file->addFilter('Rename', false, 'Filename_'.$values['id']);
    if (!$element->file->receive()) {
        print_r($element->file->getMessages());
    }
}

Remember, to have this working you need to call setValueDisabled() otherwise the file is transferred when calling getValues(). When you omit the call then your file will be transferred, due to getValues(), but it will not be renamed, because the rename filter was not available at the time, the file has been received.

Note, that using a filename based on a user input is always a security issue. Use a autoincremented number from your database for example, or be sure that you validate the user input before using it as new filename.

You should also note that I did not use another instance of Zend_File_Transfer…
The file element itself has already a instance available. When you really need to have the instance itself, then use getTransferAdapter() instead of creating a new instance. This is faster, uses less ressources and prevents possible problems with files already being transferred by the other instance.

Greetings
Thomas Weidner
I18N Team Leader, Zend Framework

Zend Framework Advisory Board Member
Zend Certified Engineer for Zend Framework

Back to top