File uploads with Zend_Form_Element_File
Now that Zend Framework 1.7 has been released, I thought I'd take a look at the built in file upload element, Zend_Form_Element_File, and see how it can be used. This is how to use it in its most basic form.
I decided to use the same set of form elements as before in order to make things easy.

Let's start with the form:
The form
We extend Zend_Form and store it in the application/forms folder and so the class name is forms_UploadForm:
<?php class forms_UploadForm extends Zend_Form { public function __construct($options = null) { parent::__construct($options); $this->setName('upload'); $this->setAttrib('enctype', 'multipart/form-data'); $description = new Zend_Form_Element_Text('description'); $description->setLabel('Description') ->setRequired(true) ->addValidator('NotEmpty'); $file = new Zend_Form_Element_File('file'); $file->setLabel('File') ->setDestination(BASE_PATH . '/data/uploads') ->setRequired(true); $submit = new Zend_Form_Element_Submit('submit'); $submit->setLabel('Upload'); $this->addElements(array($description, $file, $submit)); } }
As before, we set the name and enctype attribute of the form to allow for files to be uploaded. The form itself has two fields: a text field called 'description' and the file upload field called 'file', along with a submit button. Nothing especially complicated here.
The Zend_Form_Element_File element has a setDestination() method which is used to tell the underlying Zend_File_Transfer_Adapter_Http where we want the file that is uploaded to be stored. In this case we choose data/uploads.
The controller & view
The controller is also very standard:
<?php class IndexController extends Zend_Controller_Action { public function indexAction() { $this->view->headTitle('Home'); $this->view->title = 'Zend_Form_Element_File Example'; $this->view->bodyCopy = "<p>Please fill out this form.</p>"; $form = new forms_UploadForm(); if ($this->_request->isPost()) { $formData = $this->_request->getPost(); if ($form->isValid($formData)) { // success - do something with the uploaded file $uploadedData = $form->getValues(); $fullFilePath = $form->file->getFileName(); Zend_Debug::dump($uploadedData, '$uploadedData'); Zend_Debug::dump($fullFilePath, '$fullFilePath'); echo "done"; exit; } else { $form->populate($formData); } } $this->view->form = $form; } }
The view, views/scripts/index.phtml, is trivial:
<h1><?= $this->title; ?></h1> <?= $this->bodyCopy; ?> <?= $this->form; ?>
If the form validates correctly, the $uploadedData array will contain the values of the form fields along with the filename of the file that was uploaded. Note that this filename is not fully qualified, so if you need the entire path to the file, then use the getFileName() method on the file element.
Conclusion
That's all there is to it for simple uploading of forms. There are still a few fairly important bugs in the component that we'll have to wait for 1.7.2 for. Specifically the Count validator doesn't always work as you'd expect and don't use getValues() and receive() as it isn't yet clever enough to know not to call move_uploaded_file() more than once.
As usual, here's a zip file of the project I created to test this: Zend_Form_Element_File_Example.zip (including Zend Framework (a snapshot of the release-1.7 branch) which is why it's 3.9MB large).

November 30th, 2008 at 13:02 #
For Zend_Form you can use the "init"-function. Look at the quick start tutorial: http://framework.zend.com/docs/quickstart/create-a-form
November 30th, 2008 at 13:54 #
John,
Yep - init() in place of using the standard constructor works fine.
Regards,
Rob...
December 1st, 2008 at 15:00 #
Hi Rob my name is gonzalo benitez i have a question.. i am developing a multilanguage website, and i had choosen the array form notation to display the options like filter, validators, labes etc.- because it seemed faster and better to me. The problem is that is more dificult to translate with poedit because the strings. What do you think about it?
December 1st, 2008 at 19:34 #
Gonzalo,
I think you'll get a better answer on the i18n mailing lists where there are people who understand translation issues much better than I do!
Regards,
Rob...
December 1st, 2008 at 20:48 #
Thanks anyway! great example cheers
December 2nd, 2008 at 09:18 #
Hi Rob, thank you for sharing. (I found the bug about count validator too)
Maybe I'm wrong but it seems to be not possible use 'setErrorMessages()' as method of Zend_Form_Element_File as usually used for remaining fields. There's any workaround for this?
Regards,
Fabrizio
December 5th, 2008 at 18:29 #
You should also have mentioned that the implementation of Zend_Form_Element_File is delivered with many validators and some filters which allow much more flexibility than a simple upload.
For your information: getValues() does not return the full path for security reasons.
Btw: The multiple receivement bug was fixed on the same day you reported it.
Greetings,
Thomas ( the one who made this component :-) )
December 5th, 2008 at 19:04 #
Hi Thomas,
Yeah - there are many validators available for Zend_Form_Element_File, but I didn't want to complicate the basic usage :)
I was glad to see the multiple receive() issue solved so quickly, but it's a shame it missed 1.7.1. I should have played with this stuff a week or so earlier!
Regards,
Rob...
December 8th, 2008 at 02:41 #
Nice post. Thank you for the info. Keep it up.
January 24th, 2009 at 16:34 #
Doesn't this cause race conditions when multiple users concurrently upload a file named a.ext?
January 24th, 2009 at 17:06 #
Sebastian,
Probably :)
Rob...
January 24th, 2009 at 17:32 #
But of course only when they upload the same file within the same millisecond. :-)
And that's a rare race condition (you would get an error/exception as user in this case)
Greetings
Thomas
February 15th, 2009 at 23:32 #
I'm working on a project using Zend_Form_Element_File myself right now, and I'm interested in how you'd handle a situation where you need to rename the file based on a database quey (lastinsertid.) Its pretty obvious that this element is fairly new, because its really a major security flaw to not have anything in place to easily rename the uploaded file based on critera like a userid or a pictureid. You can set it to not overwrite an existing file, at least closing the hole of your admin's profile getting overwritten with goatse, but that also makes it quite hard to upload generic sounding files (how many people might name a file profile.jpg? I'm guessing more than one on the entire internet) or even impossible in a situation where you're collecting the same exact file from people ("Upload config.ini here please.") Right now the only way I can see to do this cleanly would be to massively extend the file element, and have my own functions for recieve etc in my class that take an id or something. The only other thing I could think of was do an if(isuploaded) and then go in and setdestination() after doing whatever needs to be done to make it a unique filename.
February 16th, 2009 at 06:55 #
@Zach:
Don't you think that this is quite unhandy ?
Wouldn't it be better to use the Rename Filter instead of extending the form element ? ;-)
Greetings
Thomas
February 16th, 2009 at 15:36 #
Its kind of a chicken and the egg thing, unless I'm missing something though. I'm really new to Zend Framework so I'd love if you could correct me, but I want to rename the file with a unique id number, but I can only create that unique ID number after the file has uploaded and and the move filter has been triggered?
Or could I set the filter after isuploaded() but before receive()?
February 16th, 2009 at 16:11 #
Simplified:
if (isUploaded) {
$adapter->addFilter('Rename', $myownname);
if (isValid) {
$adapter->receive();
} else {
print "Oops";
}
}
Greetings
Thomas
February 16th, 2009 at 16:36 #
Thanks!
March 9th, 2010 at 18:49 #
I used Zend_Form_Element_File to upload a file to webserver through a Zend_form class. How could I use the same class to download the file uploaded previously? I would appreciate any help.
Thank you,
Flávio.