Zend Framework: File upload using Zend_Form_Element_File

hello All ,

This post will be helpful for all people who are wishing to get some practicle example for using ‘Zend_Form_Element_File’ of Zend framework’s ‘Zend_Form’.
There will 3 steps to implement it:

  1. Create form with ‘enctype’ set to ‘multipart/form-data’ using Zend_Form
  2. Create File upload box using Zend_Form_Element_File
  3. Upload the file on server and get uploaded file’s detail for saving in database

So Let’s explore these steps one by one:

Step 1: Create form with ‘enctype’ set to ‘multipart/form-data’ using Zend_Form

Setting Form ‘enctype’ to ‘mutipart/form-data’ in Zend framework appears difficult if you don’t know about it. In real it is very simple if you ever got a chance to observe setAttrib() function for setting attributes of any element. Lemme give you an example.

(For example, i am creating ‘DocumentForm’ Class that will handle Document uploading Form)

First thing that you’ll need is to set Zend_Form’s ecryption type to ‘multipart/form-data’. This is must for file uploading.
So here it goes ..

class DocumentForm extends Zend_Form
{
    public function __construct($options = null)
    {
	parent::__construct($options);
  	// setting Form name,Form action and Form Ecryption type
	$this->setName('document');
	$this->setAction("");
	$this->setAttrib('enctype', 'multipart/form-data');
    }
}

Above code will create a form named ‘document’ with encryption type ‘multipart/form-data’. Now lets move to next step.

Step2: Create File upload box using Zend_Form_Element_File

You may notice some new code in Bold here:

class DocumentForm extends Zend_Form
{
	 public function __construct($options = null)
	 {
		 parent::__construct($options);
		 // setting Form name, Form action and Form Ecryption type
		 $this->setName(’document’);
		 $this->setAction(”");
		 $this->setAttrib(’enctype’, ‘multipart/form-data’);
		 
		 // creating object for Zend_Form_Element_File
		 $doc_file = new Zend_Form_Element_File(’doc_path’);
		 $doc_file->setLabel(’Document File Path’)
				  ->setRequired(true);

		 // creating object for submit button
		 $submit = new Zend_Form_Element_Submit(’submit’);
		 $submit->setLabel(’Upload File’)
				 ->setAttrib(’id’, ’submitbutton’);

		// adding elements to form Object
		$this->addElements(array($doc_file, $submit));
	 }
}

Bold lines in above code will populate a File Element along with a Submit button on Form.

Now user will select the file for uploading and press the Submit button,so here comes our step 3.

Step 3: Upload the file on server and get uploaded file’s detail for saving in database

This is last but most important step of the process that saves the file on server and returns back file upload details. Above Form will be called by some Controller’s Action so here comes my Controller and Action that will show and handle this form.

class DocumentForm extends Zend_Form
{
 function addAction()
 {
 $form = new DocumentForm();
 $this->view->form = $form;

 if ($this->_request->isPost()) {

 $formData = $this->_request->getPost();
 if ($form->isValid($formData)) {

 /* Uploading Document File on Server */
 $upload = new Zend_File_Transfer_Adapter_Http();
 $upload->setDestination("/uploads/files/");
 try {
 // upload received file(s)
 $upload->receive();
 } catch (Zend_File_Transfer_Exception $e) {
 $e->getMessage();
 }

 // so, Finally lets See the Data that we received on Form Submit
 $uploadedData = $form->getValues();
 Zend_Debug::dump($uploadedData, 'Form Data:');

 // you MUST use following functions for knowing about uploaded file 
 # Returns the file name for 'doc_path' named file element
 $name = $upload->getFileName('doc_path');

 # Returns the size for 'doc_path' named file element 
 # Switches of the SI notation to return plain numbers
 $upload->setOption(array('useByteString' => false));
 $size = $upload->getFileSize('doc_path');

 # Returns the mimetype for the 'doc_path' form element
 $mimeType = $upload->getMimeType('doc_path');

 // following lines are just for being sure that we got data
 print "Name of uploaded file: $name 
";
 print "File Size: $size 
";
 print "File's Mime Type: $mimeType";

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

 exit; 
 } 

 } else {

 // this line will be called if data was not submited
 $form->populate($formData);
 }
 }
}

and thats it!

please let me know if you guys feel anything more to add in it. :)For more advancements in above code, please see the File upload manual here: http://zendframework.com/manual/en/zend.file.html
Advertisements

55 thoughts on “Zend Framework: File upload using Zend_Form_Element_File

  1. thomas says:

    There are few problems with your code… fix these:

    *) Why do you create two identical file adapters ?
    There is already an adapter within the file element, so there is no need to create it manually.

    This will lead to failures.

    *) You are referring to the last bracket as “will be called when no data is submitted”… this is not true as you will get there when the validation fails… for example, when the submitted file is too big.

    Greetings
    Thomas

    • Ahsan Shahzad says:

      hi Thomas,

      Thanks for your problem indications,
      i have fixed the missing things in my code and it will work fine now (tested),

      I pasted this code from my project so few extra things remained in it but now it is fine. I have tried to keep this example very simple while giving complete idea about file upload Zend_Form_Element_File

  2. Faheem Abbas says:

    Great work.
    I would like to add one thing….
    use
    Zend_Debug::dump($_FILES);

    in place of

    print_r($_FILES);

    and check your results.

  3. thomas says:

    Currently you are not checking if the file has been received.

    Note that within the latest release receive() returns ONLY a boolean and no exception.

    And you should mention that due to the setRequired(true) line a user MUST upload a file, he is not able to send the form without an attached file what sometimes is recommended.

    • Ahsan Shahzad says:

      Thomas, thanks for taking interest for realizing me the missing stuff. I have added the things that you suggested and hopefully this tutorial will be easy to use for some beginner.

      About this comment line: ‘Currently you are not checking if the file has been received.‘,
      i am depending on this condition in my code “if ($form->isValid($formData))“. As i have kept my file element as Mandatory [due to setRequired(true) ] so i don’t need any special handling here.

  4. thomas says:

    What I forgot:

    It is not recommendable to use $_FILES plain. If using so, your user could manipulate the data which is sent and you would not notice this.

    The values are all checked, corrected and served by the file adapter itself. Additionally you are missing some nice and sometimes necessary additions.

    See the manual or my blog:
    ->getFileName()
    ->getFileSize()
    ->getFileInfo()
    ->getMimeType()
    ->getHash()

    All this methods do not trust the data which is provided by the user.

    • Ahsan Shahzad says:

      Thomas, thanks again for your guidance.
      I was thinking to keep this example very simple but now i have added usage example for your suggested functions too.

      so there shouldn’t be any Security issues …

  5. Grahf says:

    Hello I created a simple Form and added it an Zend_Form_Element_File, and I wanted to manipulate the form action by the ajaxForm jquery method,

    public function getImportForm($render)
    {
    require_once ‘Zend/Form.php’;
    $form = new Zend_Form();

    $form->setAttrib(‘id’,’importForm’);
    $form->setAttrib(‘enctype’, ‘multipart/form-data’);
    $form->setAction( $this->view->baseUrl().’leads/lead/batchimport’);

    $element = new Zend_Form_Element_File(‘import’);
    $element->setLabel(‘File to upload’);

    // ensure only 1 file
    //$element->addValidator(‘Count’, false, 1);
    // limit to 100K
    //$element->addValidator(‘Size’, false, 202400);
    $element->setRequired(true);
    // only XLS
    //$element->addValidator(‘Extension’, false, ‘xls’);

    $form->addElement($element, ‘import’);
    $form->addElement(‘submit’,’importSubmit’,array(‘label’=>’Import’));

    if($render)
    return $form->render();
    else
    return $form;

    }

    and here is the action I use in the controller

    public function batchimportAction()
    {

    if (! $this->getRequest()->isXmlHttpRequest()) {
    $this->getResponse()->setHttpResponseCode(404)->sendHeaders();
    return false;
    }
    else {
    $values = $_REQUEST ;
    $leadModel = new leadModel();
    if (isset($values[‘importSubmit’])) {
    $form= new $this->getImportForm(false);
    if($form->isValid($_POST))
    {
    $adapter= new ZeajaxActionnd_File_Transfer_Adapter_Http();
    $adapter->setDestination(‘/var/www/CAR/temp’);
    }

    $this->_helper->json->sendJson(”);
    }
    }
    }

    but when I click on it to test it sends me an unexpected end of XML.

    Could you help me with that?
    I could help if I try to create my own Form Class?
    thanks for your time

  6. Prem says:

    How do i rename uploaded file??
    I m adding filter for renaming .. but its not working.
    If any1 can give example that will help me.

    Thanks
    Prem

    • Ahsan Shahzad says:

      @Prem: Though I was intending to keep my example a bit simple but as per your request, i have added the code that Renames an uploaded File in Zend Framework. For your understanding, i am keeping that code in Green color.

      Let me know if you need any further help.

      Regards
      Ahsan Shahzad

  7. Mark says:

    Neither getFileSize or getMimeType work for me. Zend displays an error message stating that they are undefined methods. I’ve looked in the manual – they are present, but they are missing from the API.

    Any advice?

    Thanks.

    • Ahsan Shahzad says:

      @ Mark on: Which Zend framework version you are using ? Please let me know.

      getFileSize and getMimeType are valid function of Zend framework but you might be using it wrongly. So try to paste your code here.

      Thanks
      Ahsan Shahzad

  8. joel says:

    @ Mark: I’m having the same issue with the methods

    $upload = new Zend_File_Transfer_Adapter_Http();

    $name = $upload->getFileName(‘file’);
    $size = $upload->getFileSize(‘file’);
    $mimeType = $upload->getMimeType(‘file’);

  9. thomas says:

    @Mark: Use 1.8pre… this methods where in past only available within the file transfer class, and since 1.8 they are also available within the file form element.

  10. Nicky Flavier says:

    Thanks bro, very nice and simple. Oh btw, you forgot an s on setOptions:
    ………
    $upload->setOptions(array(‘useByteString’ => false));

  11. Rakoto says:

    Very good job! Bravo!
    But I have a question: where do you place the uploads folder? Under the public directory? Do I have to change it when I upload my site in a real server? Or should I use a function like the getBaseUrl() function? Thanks

  12. Vladimir says:

    Hi,

    Thanks for putting this together it really helps!

    One thing I noticed is that in step 3 you have an addAction() in your form class. The dunction refers to $this->_request which isn’t available in Zend_Form so I presume this addAction() method belongs in the controller class.

    Thanks again for a great article.

    V

  13. Alex Romanov says:

    Sometimes I think that frameworks are meant to make things Simple . I think that doing this in Vanilla PHP would be a lot easier than with all this ZF Mess

  14. Valeeum says:

    Just noticed an error:

    In Step#3:

    The following code:
    ‘class DocumentForm extends Zend_Form’

    should read something to this effect:

    ‘class ClassName extends Zend_Controller_Action.

    Basically, you should be extending Zend_Controller_Action and NOT Zend_Form

  15. Jignesh says:

    Hello Ahsan Shahzad, I like ur articles of uploading file but in these articles u have not added the functionality to store image in the database. I m new to zend framework application so please if u don’t mine then help me to how to store image in the database and retrive that image from that database and display on the form.
    Please i require urgently……..
    Regards,

    Jignesh

  16. Nodashi says:

    I try to use your exemple but i got this error :
    The file ‘xxxxxxxx’ was illegal uploaded, possible attack

    On ZF forum Thomas Wiedner says :
    two adapters try to access the files which causes a attacker violation. The file element uses it’s own adapter.

    So how do you use two differents adapters whithout this kind of errors !

  17. Dhaval says:

    Hi
    Ur Example is very nice but there is a problem in file rename the function that describe for rename file is not rename the file also it doesn’t display any error i use the code that u write in but this not work in my application..
    if any thing that we need add extra then tell me….

    my application on local host so i can use file path like this …….

    $fullFilePath = APPLICATION_PATH.’/uploads/’.$renameFile;
    $filterFileRename = new Zend_Filter_File_Rename(array(‘target’ => $fullFilePath, ‘overwrite’ => true));

    image is stored in uploads folder but it can’t be rename..

    so pls tell me if any thing wrong

    all type of help is apperciate………

  18. jake says:

    public function checkcpwd($id,$opassword)
    {
    $id = (int)$id;
    $data = array(‘member_id’=>$id, ‘password’=>$opassword);
    $row = $this->fetchRow($data,’member_id=’.(int)$id , ‘password=’.$opassword );
    }
    ***********
    iam calling this function to fetch the row from the database where the table contains the given id and password…….
    its nott working plz help me

  19. jake says:

    public function uploadAction()
    {
    $up = new Application_Form_Fuldf();
    $this->view->form = $up;
    $a = $up->getvalues(file1);
    if($this->getRequest()->isPost()) {
    if($up->isValid($_POST)) {
    $adapter = new Zend_File_Transfer_Adapter_Abstract();
    $uploadDir = $_SERVER[‘DOCUMENT_ROOT’];
    $a = $adapter->setDestination($uploadDir);

    }
    }
    }
    /**** this is my code for file upload when ever iam uploading it is uploading to my tmp folder
    how to set the destination path to my webserver
    thanks in advance

  20. jake says:

    how can we move the files from tmp location to our required destination in zend frame work 1.10
    plz give me tdhe solution for this

    thanks in advance

  21. thomas says:

    @marcio: enctype is not needed. It’s automatically set by the file element

    @jake: use setDestination() or attach a “rename” filter at the file element

    @joaquin: Probably no “finfo” and no “mime_magic_type” extension available. Then, for security reasons, it always fall back to application/octet-stream

    For all other I may point to the developer of this component: http://www.thomasweidner.com

    The official mailing list is also a good place to search for solutions to a problem.

  22. dario says:

    Hi im trying to set a multiple files upload form.

    The form has 3 file elements.

    if i upload just 1 image i get an error.
    “noFile ‘foto2’ was not uploaded”

    How can i solve this?

    This is form definition for that element

    $this->addElement(‘file’, ‘foto2’);
    $fElement = $this->getElement(‘foto2’);
    $fElement->setRequired(false);

  23. john says:

    thanks for the tutorial! =D

    i am new to zend framework.

    i just want to ask how are you going to re-position the upload button. For instance, place it next to browse button. sorry for this silly question.

    thanks.

  24. starlover says:

    Hello, some modifications;
    I needed to use $upload->setDestination(“./uploads/files/”); (with a dot in front of /uploads) and make an uploads folder inside my public folder with write acces (777)

    Also when you want to change the filename, it should be;
    $fullFilePath = ‘./uploads/files/’.$renameFile;
    instead of:
    $fullFilePath = ‘/images/’.$renameFile;

    Question;
    How does it know where to get the file that needs to be uploaded to the server?
    What i want is to have 3 file elements on my form.. with one required, so how do i detect if there is a file in one of my elements that needs to be uploaded?
    (each to another directory on my server)
    I was thinking something like this:

    $values = $this->_request->getParams();
    if($values[‘firstfileselect’]!=””)
    {
    upload first file
    }

    But it doesn’t work 😦

    Please some help..

  25. starlover says:

    Owh and perhaps you also kow how i get the file select box to only show/select jpg images… so no other files can be uploaded.

  26. starlover says:

    Hi, I got my own answers.. 🙂

    with 2 or more file elements in the form i do this in my controller:
    ————————————————
    if(isset($_FILES[‘firstfileselect’]) && $_FILES[‘firstfileselect’][‘name’]!=””)
    {
    $first_file = pathinfo($_FILES[‘firstfileselect’][‘name’]);
    //to check if it is an image file
    if($file _file[‘extension’]==”jpg” || $file _file[‘extension’]==”JPG”)
    {
    $upload = new Zend_File_Transfer_Adapter_Http();
    $upload->setDestination(“./uploads/firstfilefolder/”);
    $files = $upload->getFileInfo();
    try
    {
    $upload->receive($files[‘fullplant’][‘name’]);
    }
    catch(Zend_File_Transfer_Exception $e)
    {
    $this->view->transfererror=$e->getMessage();
    }
    }
    else
    {
    $this->view->error=”file has no jpg extention”;
    }
    }
    if(isset($_FILES[‘secondfileselect’]) && $_FILES[‘secondfileselect’][‘name’]!=””)
    {
    //same as above but now for the second file, but other destination location.
    }

    ————————————————
    My second question about getting the file select box to only show images;
    You could use accept=”image/gif, image/jpeg” in your file element, but almost no browser supports this feature, so i put the check on file extension in the code and if it is different, i show an error. (see above code)

    Greets..

  27. Technology Garden says:

    Hello everybody,
    I am used following codes in my application, i am getting any error from those codes.

    But i can’t find the uploaded file in the directory. so i think file is not transferred.

    Please someone help me.

    /* Uploading Document File on Server */
    $upload = new Zend_File_Transfer_Adapter_Http();
    $upload->setDestination(“./uploads/files/”);
    try {
    // upload received file(s)
    //$upload->receive($reportForm->getValue(‘doc_path’));
    $upload->receive($reportForm->getValue(‘doc_path’));
    } catch (Zend_File_Transfer_Exception $e) {
    $e->getMessage();
    }

    Thanks everybody.

  28. Technology Garden says:

    Hello everybody,
    I have used following codes in my application, i am not getting any error from those codes.

    But i can’t find the uploaded file in the directory. so i think the file is not transferred to that location.

    Please someone help me.

    /* Uploading Document File on Server */
    $upload = new Zend_File_Transfer_Adapter_Http();
    $upload->setDestination(“./uploads/files/”);
    try {
    // upload received file(s)
    //$upload->receive($reportForm->getValue(‘doc_path’));
    $upload->receive($reportForm->getValue(‘doc_path’));
    } catch (Zend_File_Transfer_Exception $e) {
    $e->getMessage();
    }

    Thanks everybody.

  29. ahmed sellami says:

    i recieve this error [Tue Apr 03 09:19:59 2012] [notice] child pid 3230 exit signal Segmentation fault (11)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s