ZF-7768: Zend_File_Transfer_Adapter_Http

Description

It seems that the problem is with the fact that ajaxForm doesn't put anything in $_FILES if no file is specified, it wasn't a problem with the post size, sorry for wasting time.

can someone delete this issue since it doesn't really belong here.


I created a Zend_Form_Element_File object, and set isRequired to false, but when I have no file uploaded, the form returns false when validating.

I debuged the validate operation and I can see that the that Zend_File_Transfer_Adapter_Http tries to set the ignoreNoFile option to every file

    if (!$this->isRequired()) {
        $adapter->setOptions(array('ignoreNoFile' => true), $this->getName());
    }
    .......

but when it validates it doesn't take in account this options and returns false

    if($adapter->isValid($this->getName())) {
        $this->_validated = true;
        return true;
    }

the code above is from the zend library (that's where I think the problem is) my code is below the form file

            $image = new Zend_Form_Element_File('imageUpload');
    $image->setLabel('Upload an image:');
    $image->setValueDisabled(true);
    //  1 file
    $image->addValidator('Count', false, 1);
    //  limit 100K
    $sizeLimit = 102400;
    //  server limit
    $image->addValidator('Size', false, $sizeLimit);
    //  client limit
    $image->setMaxFileSize($sizeLimit);
    //  JPEG, PNG, GIFs
    $image->addValidator('Extension', false, 'jpeg,jpg,png,gif');

            .....
            if($mode == 'update') {
                    ....
        $image->setRequired(false);
            }

and processing the form:

        $form = $this->_getCategoryForm('update');
        if(array_key_exists('submitButton', $values)) {
            //  submit form, save changes
            //$form->populate($values);
            if ($form->isValid($values)) {                       <- here it returns false if I don't have a file uploaded. I debugged it, and the problem is with the file element

should I upload the entire php script ?

Comments

The second line you've mentioned sets the option on the adapter... it calls "setOptions"... no need to set a already stored option once again. Also, the adapter has no second option on the isValid method which could be given... I'm sorry to say that but your expectation is wrong.

When you have a problem, then you should give a example of your own code showing the problem, otherwise we can not see where your problem is.

added some code

I think it would still be interresting to know the reason for the returned validation error. According to manual a simple "$form->getMessages()" should help.

it returns:

The file 'imageUpload' exceeds the defined ini size

I don't have anything related to this in my aplication.ini file. I forgot to mention, maybe it's important that I used ajaxForm on my form when submiting (the JQuery Form Plugin) but the post still looks ok: (the imageUpload is empty as it should)

MAX_FILE_SIZE 102400 description desc idCategory 57 idParentCategory 1 image /images/category/logo.gif imageUpload name cat11sbrgbdf submitButton update visible 0

How do you come to the conclusion that post is ok because imageUpload is empty ?

imageUpload is empty because isValid returns false. Files are uploaded within $_FILES, forms are uploaded within $_POST. They are completly independend from each other.

How do you come to the conclusion that the ignoreNoFile option does not work, when you are getting an upload error returned which writes "exceeds" ?

This message "The file 'imageUpload' exceeds the defined ini size" is returned by checking the size of the uploaded file.. there must be something uploaded, because this error is thrown by PHP itself.

When there would be nothing and you would not have set ignoreNoFile, then you would get returned "The file 'xxx' was not uploaded" in the case you don't give a file to upload.

And the "ini"-setting has nothing to do with your application.ini... it mocks about your PHP.INI.

as I said before I didn't upload anything, here are the variables just before entering $file->isValid

$_FILES Array [0] $_POST Array [9]
idCategory 1
idParentCategory 0
name categorie1gbvv
description descriere1
visible 1
MAX_FILE_SIZE 102400
imageUpload image /images/category/logo.gif
submitButton update
$_GET Array [0]

here is the adapter at the call: $adapter->setOptions(array('ignoreNoFile' => true), $this->getName());

$adapter Zend_File_Transfer_Adapter_Http _break Array [4]
_filters Array [0]
_loaders Array [2]
_messages Array [0]
_translator _translatorDisabled false
_validators Array [4]
_files Array [0]
_tmpDir _options Array [3]

the same adapter just before the call $adapter->isValid($this->getName())

$adapter Zend_File_Transfer_Adapter_Http _break Array [4]
_filters Array [0]
_loaders Array [2]
_messages Array [0]
_translator _translatorDisabled false
_validators Array [4]
_files Array [0]
_tmpDir _options Array [3]

then in isValid

CONTENT_LENGTH 171

the $files is the name of the element

public function isValid($files = null)
{
    // Workaround for a PHP error returning empty $_FILES when form data exceeds php settings
    if (empty($this->_files) && ($_SERVER['CONTENT_LENGTH'] > 0)) {
        if (is_array($files)) {                                                                     
            $files = current($files);
        }

here is the first part from $_SERVER, maybe it helps... $_SERVER Array [40]
[0...30]
REDIRECT_APPLICATION_ENV development REDIRECT_STATUS 200 APPLICATION_ENV development HTTP_HOST magazin.local
HTTP_USER_AGENT Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.13) Gecko/2009080315 Ubuntu/9.04 (jaunty) Firefox/3.0.13
HTTP_ACCEPT */* HTTP_ACCEPT_LANGUAGE en-us,en;q=0.5
HTTP_ACCEPT_ENCODING gzip,deflate
HTTP_ACCEPT_CHARSET ISO-8859-1,utf-8;q=0.7,*;q=0.7
HTTP_KEEP_ALIVE 300 HTTP_CONNECTION keep-alive
CONTENT_TYPE application/x-www-form-urlencoded; charset=UTF-8
HTTP_X_REQUESTED_WITH XMLHttpRequest
HTTP_REFERER http://magazin.local/category/…
CONTENT_LENGTH 171 HTTP_COOKIE PHPSESSID=1527db8c855c4cd747aafbf18907decb; XDEBUG_SESSION=ECLIPSE_DBGP HTTP_PRAGMA no-cache
HTTP_CACHE_CONTROL no-cache
PATH /usr/local/bin:/usr/bin:/bin SERVER_SIGNATURE

Apache/2.2.11 (Ubuntu) PHP/5.2.6-3ubuntu4.2 with Suhosin-Patch Server at magazin.local Port 80
\n SERVER_SOFTWARE Apache/2.2.11 (Ubuntu) PHP/5.2.6-3ubuntu4.2 with Suhosin-Patch
SERVER_NAME magazin.local
SERVER_ADDR 127.0.0.1
SERVER_PORT 80
REMOTE_ADDR 127.0.0.1
DOCUMENT_ROOT /home/alin/www/magazin.local/public SERVER_ADMIN webmaster@localhost SCRIPT_FILENAME /home/alin/www/magazin.local/public/index.php
REMOTE_PORT 35143
REDIRECT_URL /products/category/update
GATEWAY_INTERFACE CGI/1.1

When $_FILES is empty and CONTENT_LENGTH is bigger than 0, then you have a PHP error. You copied the related note yourself:


// Workaround for a PHP error returning empty $_FILES when form data exceeds php settings

Note: $_FILES will not be empty... it is filled even if you do not provide a file because the related data is within your form. The only case where $_FILES is empty is when the $_POST data from your form exceed the allowed size within your ini file.

The only other case would be when you call Zend_File_Transfer manually when there is no form at all.

Change your ini settings to allow retrievment of all data which may be entered to prevent this php bug.

Closing as incomplete.

I have the same issue with the same setup above. My adapter correctely shows the 'ignoreNoFile' option:


// Zend_Debug::dump($file->getTransferAdapter()->getOptions());
array(1) {
  ["file"] => array(1) {
    ["ignoreNoFile"] => bool(true)
  }
}

I do not POST my form directely but parse an ajax result like this:


$post = array('name' => 'foo', 'file' => null);

if (!$form->isValid($post)) {           
    // ...      
}

The form remains invalid with no further error message. I guess this means that the 'ignoreNoFile' option does not work as expected.

One possible workaround is overriding the forms's isValid() method to check if the 'file' has been "posted". If not then the element itself could be removed.

Important: this problem never occurs when using a regular POST inside your browser. It happens only when receiving an ajax post f.e. or setting it by hand (see my example).