views:

354

answers:

1

I am experimenting with uploading files in a Zend_Form using the Zend_Form_Element_File doing something like this in my form so that the actual upload can be handled by my controller (which in my case is to eventually do some custom file re-naming on the fly).

$element = new Zend_Form_Element_File('Upload');
$element->setDestination(UPLOAD_PATH)
         ->setValueDisabled(true);
$submit = new Zend_Form_Element_Submit('submit');

In the controller action I then have (very simplified) code like the following which works well:

$form = new MyForm();
$this->view->form = $form;

if ($this->getRequest()->isPost()) {
  $formData = $this->getRequest()->getPost();
  if ($form->isValid($formData)) {
    $form->Upload->receive();
    $this->_redirect('/nextAction');
  } else {
    $form->populate($formData);
  }
}

However (and here it comes) what I want to do is have a cancel button on my form handled like this:

[Form]
$cancel = new Zend_Form_Element_Submit('cancel'); 

[Controller]
if ($this->getRequest()->isPost()) {
  $formData = $this->getRequest()->getPost();
  $cancel = $this->getRequest()->getPost('cancel');
  if ($cancel == 'Cancel') {
    $this->_redirect('/nextAction');
  }
  if ($form->isValid($formData)) {
    $form->Upload->receive();
    $this->_redirect('/nextAction');
  } else {
    $form->populate($formData);
  }
}

The trouble starts when the user selects a file via 'Upload' and then hits 'cancel' to exit out of the action. The form doesn't know the difference between 'Submit' and 'Cancel' and initiates the transfer from the browsers end. On the server end the receive() function isn't called and that hangs the entire process.

In this older (Non-Zend) SO question "Cancel a webform submit with php" the suggested answer is to have the cancel button in a separate form. I don't think that this is what I want to do in a Zend based system.

In this old (Zend) forum question "Zend Form Element File upload issues" the suggested answer for canceling an upload is to do something like this:

  if ($cancel == 'Cancel') {
    unlink($form->Upload->getValue());
    $this->_redirect('/nextAction');
  }

I have tried this and it seems to work, but I don't know why and when I look behind the curtains I actually see that it generates an error of the form:

Warning: unlink(<filename>): No such file or directory in <line in controller code where unlink() call is> 

So my big question is what is the best way to be canceling out of the file upload? (and what does the unlink do - even with the error?)

Thanks

Edit 3/3

To clarify, HTML form uploads are pretty dumb. If you have multiple submit buttons on a form that has a File element, then no matter what submit button you seem to use the file gets transferred to the temp upload directory on your server.

But Zend tries to be clever, it allows you to defer copying the file from the temp directory to the final destination through "setValueDisabled(true)" in the form and "receive()" in the controller.

However if you initiate an upload in the form, but do not call "receive() in the controller, then the entire Zend process seems to lock up (I get the browser continually announcing "loading" and doing nothing else).

I am looking for a Zend (or pure php) based solution to back out of the file upload on the server side, after the file has arrived in the temp directory, but before a call to "receive()" is required.

The "unlink" method seems to work, but it also throws a warning and as I have no real idea of why it works I am suspicious of what is actually going on.

A: 

Try if ($cancel->isChecked()) instead of if ($cancel == 'Cancel')

EDIT

This is how file uploads work. The form is submitted, and the browser sends the file, through HTTP to server. PHP sees a form with enctype "multipart/form-data" and a file element, and saves that file in a temporary location. At this point, if you call "Receive", it actually calls, behind the scenes, the PHP functions which move that file out of its temporary location.

Once you hit submit, the browser sends the file, whether you like it or not. You can choose to ignore the file, which is what it looks like you're trying to do. However, if ($cancel == 'Cancel'), doesn't look it will work because the value is case-sensitive. To avoid error-prone code like this, if ($cancel->isChecked()) is preferred.

Can you be a little more specific on what exactly you're trying to do?

blockhead
That is just how I detect that the Cancel was called, and while that is probably what I should be doing, how will this terminate the upload?
Peter M
I've expanded my answer a little.
blockhead
After doing lots of poking around I do understand that the file gets transferred regardless of what you do. You are right that I am trying to ignore the uploaded file and have edited my question. The whole "cancel" issue is another discussion. First of all the case sensitivity of what I am doing is correct, so the code is following the paths I expected it do. I have been reading up a little on isChecked() and my gut feeling is that I need to load the form with the posted data prior to using it. If so then that only changes the basic layout of my actions (not a biggie).
Peter M

related questions