Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_File_Transfer Component Proposal

Proposed Component Name Zend_File_Transfer
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_File_Transfer
Proposers Thomas Weidner
Matthew Weier O'Phinney (Zend Liaison)
Revision 1.0 - 27 Apr 2007: Initial release
1.1 - 03 May 2007: Small reworks to the API
1.2 - 05 May 2007: Added hook for check as discussed
2.0 - 06 Aug 2007: Renamed to Zend_Http_Upload
3.0 - 22 Dec 2007: Renamed to Zend_File_Uploader and completly
reworked the API
4.0 - 20 Jan 2008: Renamed to Zend_File_Transfer, API reworked (wiki revision: 28)

Table of Contents

1. Overview

Zend_File_Transfer is a component to handle File Up- and Downloads within the Zend Framework in a standardized way.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

No requirements...

But to receive upload-processing informations a pecl extension and minimum PHP 5.2 is needed.
Otherwise the class can not provide the processing information.

4. Dependencies on Other Framework Components

  • Zend_Exception

5. Theory of Operation

This component is meant to handle file up- and downloads within the Zend Framework. Is should provide an simple and generic way for all users. Several tasks are possible:

  • Upload multiple files
  • Set validators
  • Set filters
  • Set paths
  • Rename files
  • Provide a way to get the download progress data for the handled
    files (could be limited to 5.2)
  • Wrapper for downloads
  • Different adapters for HTTP POST, WEBDAV, FTP, AJAX and so on...

6. Milestones / Tasks

  • Milestone 1: [FINISHED] Proposal finished
  • Milestone 2: [FINISHED] Proposal accepted
  • Milestone 3: Working release
  • Milestone 4: Unit tests
  • Milestone 5: Documentation
  • Milestone 6: Future enhancements

7. Class Index

  • Zend_File_Transfer_Exception
  • Zend_File_Transfer
  • Zend_File_Transfer_Protocol
  • Zend_File_Transfer_Protocol_Http
  • Zend_File_Transfer_Procotol_Ftp
  • Zend_File_Transfer_Procotol_WebDav
  • Zend_File_Transfer_Procotol_Ajax

8. Use Cases

Upload defined file

Default for transfer is http download. This code shows the simplest way to have downloads integrated.

Set validators

Validators can be used to check several options of files which are loaded. Validators could possibly be Zend_Validate validators... but this would be checked at time of integration. Not sure if this would fit all needs. But Zend_File_Transfer will integrate several own validators like FileSize, FileExtension, MimeType and so on...

Validators for single files/fields

Validators can also be set for single files, or for all. Also isUploaded can check for all or single files. Of course the API supports fluid interface where applicable.

Change content with filters

With filters it is possible to change content of downloaded files before they are stored. Doublicate transfered files to a second directory, or change content with self written filters in this example change linebreaks of textfiles from unix to windows. Several filters are thinkable.

HTTP PUT Uploads

Also other adapters can be used. In our example http put, but also other adapters like FTP, WEBDAV or AJAX will be integrated. Within all adapters the API will be the same.

FTP Downloads

The API can also be used for downloads. It will work as wrapper so the user does not see where the original files is located and ZF will send the file to the user.

WebDav Uploads

All adapters use the same API... here WebDav

Ajax Uploads

There is also an idea of creating an Ajax adapter which would make it possible to upload files in a form while the user has not to wait until the upload is finished and can work on the form or make other things while the file is uploaded in background with ajax. Also the status (amount of downloaded files, progress and so on) is avaiable to the user while the upload is in progress and can be displayed to him as additional information.

Actually there is no code because this will also have to be integrated in the form or the view the user get's displayed.

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Apr 27, 2007

    <p>a) How is this easier than using the native functions?<br />
    b) When I have multiple file uploads, often I want to move them to different locations<br />
    c) If this were to be adopted, shouldn't it maybe be <code>Zend_File_Upload</code> instead?</p>

    1. Apr 27, 2007

      <p>a) Until now I often saw people creating own classes for handling file uploads... I just wanted to give a standard way for ZF users... as with all other ZF classes... you dont need to use them if you do not want to... My opinion is that a standard way is better than no way with everybody cooking his own soup.</p>

      <p>b) This is supported... see setDestination/move... for each file or a collection of files a destination can be set</p>

      <p>c) It was your name-cousine (Matthew-Weier-O'Phinney) who choose the name in january... see ZF-818<br />
      Zend_File_Upload expects the user to have other file manipulating classes like _Download _Compress _Copy and so on... I am not related to Zend_Update... I just wanted to have a simple, small name and this one was already written several times ago within the mailing list</p>

      1. Apr 27, 2007

        <p>Re: c) Matthew's opinion isn't a divine writ. <ac:emoticon ac:name="wink" /> In any event, he said "Zend_Upload (or similarly named)".</p>

        <p>I anticipate other <code>Zend_File</code>-related classes (in fact, I am developing some now in conjunction with my as-yet unproposed <code>Zend_Io</code>). Makes sense to plan for the future instead of having related classes all over the place.</p>

        1. Apr 29, 2007

          <p>I already mentioned that I am not related to Zend_Upload...<br />
          I just want to serve the functionallity to the Zend Framework.</p>

          <p>But what you wrote is quite confusing to me... <ac:emoticon ac:name="wink" /><br />
          On one side you wrote "shouldn't it be Zend_File_Upload instead"<br />
          and on the other side you wrote "you anticipate other Zend_File related classes".<br />
          What about Zend_Http_Client_Form_Download_Multiple_Files_With_This_Class ? <ac:emoticon ac:name="wink" /> <ac:emoticon ac:name="wink" /></p>

          <p>But however we name it, are there any neg's for providing a standardized way of handling file uploads ?? (and maybe file downloads in the future) <ac:emoticon ac:name="wink" /></p>

          1. May 02, 2007

            <p>Don't get me wrong; I'm in favor of this class. It would replace my own file upload class. It's just been said again and again that classes that wrap PHP functions without adding value (beyond object-orientation) won't be approved for inclusion. If this is approved, this class pushes the door open for the inclusion of other wrapper classes.</p>

  2. May 03, 2007

    <p>Thomas, I like it as is. No more further suggestions. <ac:emoticon ac:name="smile" /></p>

  3. May 03, 2007

    <p>One comment:</p>

    <p>Zend_Upload's constructor is still PHP-4 style (using the class name), but that's a minor issue __construct would be more suitable.</p>

    1. May 03, 2007

      <p>Of course you are right <ac:emoticon ac:name="wink" /><br />
      Blame on me <ac:emoticon ac:name="smile" /></p>

  4. May 04, 2007

    <p>I have ever made my own upload class to extend Zend Framework and I use it like this (very similar than you):</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    try

    Unknown macro: { $upload = new Smoos_Http_Upload();$file = $upload->getFile('myfile') ;$file->setValidExtensions(array('jpg','jpeg','gif','png'),'accept'); //or deny$file->nameToSafe();$file->moveTo(/'home/www/images/'); }

    catch (Smoos_Http_Upload_Exception $e) {}
    ]]></ac:plain-text-body></ac:macro>
    <p>I can manage if extention are accepted or not not accepted...</p>

    <p>Also, why not Zend_Http_Upload ?</p>

  5. Jul 11, 2007

    <p>a) I would prefer Zend_Http_Upload too..</p>

    <p>b) Did you took file-arrays in consideration? "<input type="file" name="name[]" />" ..</p>

    <p>c) Maybe it's possible to use Zend's Filters and Validators for file-name-validation - but on the other hand this might bloat the class.. <ac:emoticon ac:name="smile" /></p>

    <p>c) I like your current ideas for methods, but I would prefer a bit more control over file-handling. Hence I would propose a more object-style structure:</p>

    <ul>
    <li>Zend_Http_Upload (or whatever the final package will be)</li>
    </ul>

    <ul>
    <li>Zend_Http_Upload_Group<br />
    Primary used to group files with same options to make validation easier. As example: You want an upload-form with 20 files, where 10 should be .doc with a maximum filesize of 10kb and 10 should be images with a max. filesize of 100kb, you can use this class to make 2 groups with the specific settings.</li>
    </ul>

    <ul>
    <li>Zend_Http_Upload_File<br />
    Like "Group", but on a per-file base. This class can be passed to "Upload" and "Upload_Group" instead of field-names. The developer can define some settings (max filesize, allowed filetypes) here, as well as in "Upload" and "Upload_Group".<br />
    This class could also be extended, to include support for some more specific cases - e.g. "Upload_File_Image" could be easily written to validate images (their types, their size, etc.).<br />
    For this, there will be the need to return some usefull error-information to developers, so they know why a file is not valid.</li>
    </ul>

    <p>Thus there will be three layers of validations. On global scope ("Upload"), on a per-group scope ("Upload_Group") and on a per-file scope ("Upload_File").</p>

    <p>This would be really complicated and bloated if you simply want to check if a file is within a specific filesize, so it should be possible to use just the first layer (see examples below).</p>

    <p>I'm currently not a registered developer here, but if these ideas turn out to be useful I could help, if help is needed. <ac:emoticon ac:name="smile" /></p>

    <p><strong>Some examples</strong></p>

    <p>Simplest validation-example:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $upload = new Zend_Http_Upload();

    // alternative syntax: addFile(new Zend_Http_Upload_File('docfile'));
    $upload->addFile('docfile');

    // set max size for all files (in byte)
    $upload->setMaxTotalSize(100000);

    // set max size for a single file ('docfile' can just be 50kB big, not 100kB)
    $upload->setMaxSingleSize(50000);

    // syntax from Sylvains class
    $upload->setValidExtensions(array('doc', 'odt', 'xml'), 'accept');

    // catch all errors from all files at once (constant randomly named)
    if($upload->isValid() != UPLOAD_ERROR_NONE) {
    // display error..
    } else {
    // process upload..
    }

    // catch just errors from 'docfile' (in our case this is like the first example)
    if($upload->docfile->isValid() != UPLOAD_ERROR_NONE) {
    // display error..
    } else {
    // process upload..
    }
    ]]></ac:plain-text-body></ac:macro>

    <p>A bit more complicated example:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $upload = new Zend_Http_Upload();

    // init new image-upload
    $image = new Zend_Http_Upload_File_Image('photo');

    // image can just have a filesize of 100000 byte
    $image->setMaxSize(100000);

    // set min and max image size (using image-functions)
    $image->setMinDimension(100, 100);
    $image->setMaxDimension(500, 500);

    $upload->addFile($image);

    $photoValid = $upload->photo->isValid();

    if($photoValid == UPLOAD_ERROR_IMG_MINSIZE) {
    // error no. 1
    } else if($photoValid == UPLOAD_ERROR_IMG_MAXSIZE) {
    // error no. 2
    } else if($photoValid != UPLOAD_ERROR_NONE) {
    // general error
    } else {
    // proccess upload..
    }
    ]]></ac:plain-text-body></ac:macro>

  6. Jul 12, 2007

    <p>hi,</p>

    <p>this is a good idea I think...</p>

    <p>Do you check the file type on the file extension, or on the mime type?<br />
    (does this question make sense?)</p>

    <p>vincent</p>

    1. Jul 12, 2007

      <p>If your comment was a reply to mine:</p>

      <p>Since the methods name is "setValidExtensions(..)", the method just checks the file-extension. Because the mime-type can be changed on the browser-side, it's maybe a better idea to rely on an extension-check (<a href="http://www.addict3d.org/news/1075/.html">http://www.addict3d.org/news/1075/.html</a>, <a href="http://de2.php.net/manual/en/features.file-upload.php">http://de2.php.net/manual/en/features.file-upload.php</a>). The extension might be changed as well, but on a normal server (which just parse .php as PHP) a changed extension will also stop the server to parse the file. Are there other security issues which should be taken into consideration?</p>

      <p>Greetings, Florian</p>

  7. Jul 30, 2007

    <p>1) In my opinion validating a file name by its extension is not the safest way to handle file uploads.</p>

    <p>2) I must agree that Matthew Ratzloff is write better rename it Zend_File_Upload because probably in the future many operations with files will be implemented (for sure archiving would be a good idea).</p>

    <p>3) The third thing that i don't understand is the if chains:</p>

    <p>if($photoValid == UPLOAD_ERROR_IMG_MINSIZE) {<br />
    // error no. 1<br />
    } else if($photoValid == UPLOAD_ERROR_IMG_MAXSIZE) {<br />
    // error no. 2<br />
    } else if($photoValid != UPLOAD_ERROR_NONE) {<br />
    // general error<br />
    } else {<br />
    // proccess upload..<br />
    }</p>

    <p>Can this be avoided? </p>

    1. Aug 06, 2007

      <p>to 1)<br />
      This is just one way to limit given files.</p>

      <p>In the proposal is also another way with the "addCheck" function which acts as callback to an self-defined checking function.</p>

      <p>How the upload is checked depends on the checks you apply to the instance.</p>

      <p>to 2)<br />
      No... better is "Zend_Http_Upload" as already stated before. As this class is not meant to handle FTP or UDP or other fileuploads...<br />
      It's designed as extension to Zend_Http.</p>

      <p>to 3)<br />
      First... never use if-chains... we have a "switch - case" statement within php <ac:emoticon ac:name="wink" /><br />
      Second... in my proposal I never stated that I will return a "UPLOAD_XXX_ERROR_CONSTANT"...</p>

      <p>What you will get is a "true" or "false" on the isxxx functions.<br />
      Or an exception when processing the files.</p>

      <p>And in my opinion an exception is the right way for the framework.</p>

  8. Jul 30, 2007

    <p>Another thing, i saw that $files->setOptions will receive an array, this may create a confusion because there are to many parameters and you are forcing someone to remember all, in my opinion the method should set the parameters but should receive only two values, key and value. It would be easier to check for consistency.</p>

    1. Aug 06, 2007

      <p>No, I dont agree with you, because almost all classes within the framework use arrays as options parameter.</p>

      <p>See Zend_Date, Zend_Db, Zend_Filter, Zend_Session, Zend_Translate and many other classes.</p>

      <p>Having scalar values as input would mean that you have to call the same method several times to set all wished options.</p>

      <p>With Arrays you can have all your options stored within an config array (Zend_Config) and simply give this array.</p>

  9. Jul 30, 2007

    <p>I agree with this idea, to make a Zend Upload object.<br />
    I belive is better to rename it Zend_Http_Upload, cuz we need to remember that maybe will be a Zend_Ftp_Upload.</p>

    <p>Nicolae,<br />
    Your 1) topic is very interesting, I must agree with that.</p>

    1. Aug 06, 2007

      <p>As already written to Nicolae...<br />
      What is checked depends on the restrictions you give for the upload.</p>

      <p>Restrictions can for example be:</p>
      <ul>
      <li>Name</li>
      <li>Type</li>
      <li>Size (max, min)</li>
      <li>Mime</li>
      <li>If it already exists</li>
      <li>...</li>
      </ul>

      <p>You can even apply an selfwritten check with "addCheck" if you for example have to check if your image includes a watermark <ac:emoticon ac:name="wink" /></p>

      <p>If you dont restrict the filetype it will not be checked.</p>

      1. Aug 10, 2007

        <p>Yes, there are a lot of ways to restrict the archive.</p>

        <p>I don't understand this "addCheck". You are saying that you can includes a watermark in the uploaded image?<br />
        But, this is more work then Zend_Http_Upload tasks. I think that one Zend_Image can do that?</p>

        <p>By the way, when Zend_Http_Upload will be integrate to the ZF?</p>

        1. Aug 10, 2007

          <p>You can think of the addCheck Method as a hook where you can plug in self created checker-functions.</p>

          <p>This could be a watermark-check, a regex-based filename check or something completly different. It depends on what you want to check...<br />
          Maybe it will also provide the possibility to change the content of the file before storing it to the server... I haven't finished thinking of all pro's and con's.</p>

          <p>Related to "when it will be integrated"...</p>

          <p>Until now I had not the time to finish my thoughts about this proposal.<br />
          Any I am not sure if it will be accepted in the actual state.<br />
          This is related to Matthews comment at 2.May.2007 about adding enough value.</p>

  10. Nov 20, 2007

    <p>Hi,</p>

    <p>Is this good coding practice? This code in progress...</p>

    <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
    class Zend_Http_Upload
    {
    /**

    • Action "replace" for when the file exists already
      */
      const ACTION_REPLACE = 'replace';

    /**

    • Action "error" for when the file exists already
      */
      const ACTION_ERROR = 'error';

    /**

    • Array of files to upload
      *
    • @var array
      */
      protected $_files = array();

    /**

    • Constructor
      *
    • @param string|array $files OPTIONAL Single or array of files (fields)
    • @param array $options OPTIONAL Array of options to set for all files
      */
      public function __construct($files = null, array $options = array())
      Unknown macro: { $this->addFiles((array) $files, $options); }

    /**

    • Add single file to upload from form
      *
    • @param string $file Single file (field)
    • @param array $options OPTIONAL Array of options to set for the file
      */
      public function addFile($file, array $options = array())
      Unknown macro: { $this->_files[$file] = $options; }

    /**

    • Add multiple files to upload from form
      *
    • @param array $files Array of files (fields)
    • @param array $options OPTIONAL Array of options to set for all files
      */
      public function addFiles($files, array $options = array())
      Unknown macro: { foreach ($files as $file)
      Unknown macro: { $this->addFile($file, $options); }
      }

    /**

    • Set options, general for all files
      *
    • 'maxsize' => maximum complete size to set
    • 'filetype' => filetypes to set, multiple delimiter-seperated
    • 'destination' => destination to move files to
    • 'exists' => what to do if the file exists
      *
    • @param array $options Array of options to set for all files
      */
      public function setOptions(array $options = array())
      Unknown macro: { foreach ($this->_files as $field => $config)
      Unknown macro: { $this->_files[$field] = $options; }
      }

    /**

    • Set maximum filesize
      *
    • @param integer $size Maximum filesize for the files
    • @param string|array $files OPTIONAL Files for which to set the maximum size, if not set for all in sum
      */
      public function setMaxSize($size, $files = null)
      {
      foreach ($this->_files as $field => $options) {
      if (is_array($files) && !in_array($field, $files))
      Unknown macro: { continue; }

      $this->_files[$field]['maxsize'] = $size;
      }
      }

      /**

      • Set mime type
        *
      • @param integer $type Mime type for the files
      • @param string|array $files OPTIONAL Files for which to set the type, if not set for all in sum
        */
        public function setFileType($type, $files = null)
        {
        foreach ($this->_files as $field => $options) {
        if (is_array($files) && !in_array($field, $files))

    $this->_files[$field]['filetype'] = $type;
    }
    }

    /**

    • Set directory to store files, can be set per single file
      *
    • @param string $destination Where to store the file/s
    • @param string|array $files OPTIONAL Files for which to set the destination
      */
      public function setDestination($destination, $files = null)
      {
      foreach ($this->_files as $field => $options) {
      if (is_array($files) && !in_array($field, $files))
      Unknown macro: { continue; }

      $this->_files[$field]['destination'] = $destination;
      }
      }

      /**

      • Set the action for when the file exists already
        *
      • @param string $action What to do when files exists
      • (REPLACE, ERROR, String* for autorename and/or other destination)
      • @param string|array $files OPTIONAL Files for which to set the action
        */
        public function setExists($action, $files = null)
        {
        foreach ($this->_files as $field => $options) {
        if (is_array($files) && !in_array($field, $files))

    $this->_files[$field]['exists'] = $action;
    }
    }

    /**

    • Move files to specified directory
      *
    • @throws Zend_Http_Upload_Exception
      */
      public function move()
      {
      foreach ($this->_files as $field => $options) {
      if (!isset($_FILES[$field]))
      Unknown macro: { throw new Zend_Http_Upload_Exception('Specified file "' . $field . '"does not exist in the FILES array'); }

    (...)

    $path = $options['destination'] . DIRECTORY_SEPARATOR . $_FILES[$field]['name'];

    if (!@move_uploaded_file($_FILES[$field]['tmp_name'], $path))

    Unknown macro: { throw new Zend_Http_Upload_Exception('Failed to upload file "' . $field . '"'); }

    }
    }
    }
    ]]></ac:plain-text-body></ac:macro>

    1. Nov 21, 2007

      <p>Actually this proposal is reviewed by the Dev-Team.</p>

      <p>I tend to begin coding when an proposal has approved because I dont want to have more work than nessesary. Therefor I did not include code for now...</p>

      <p>The problem is that when everyone uses your code before the proposal has approved and there is a change then all users have the problem that their code would not work anymore.</p>

      <p>Because they believe that you are the author which is not true <ac:emoticon ac:name="wink" /></p>

      <p>Actually there are enough "pre-classes" out there in several forums that it is not nessesary to include unofficial code here in my opinon.</p>

      <p>If this proposal is accepted I would be able to have my code included within the incubator.</p>

      <p>Related to your code:<br />
      There are only some small issues, for example defining constants which are not in use, or the constructor.</p>

      <p>So I am waiting for approvement from the dev team and I have not stopped working on this one. <ac:emoticon ac:name="smile" /><br />
      Please do not add code here or use this code. You will expect problems after this class is officially finished and the API does not match.</p>

    2. Nov 21, 2007

      <p>PS:<br />
      It would be better to force the dev-team to accept this proposal or give an statement about possible problems. <ac:emoticon ac:name="wink" /></p>

  11. Dec 13, 2007

    <p>Hello,</p>

    <p>I am wondering if you are going to make it so that different back ends can be set with the file upload as in my case I don't need to save it to the local file system as we have a holding server that holds all the upload that get a approved.</p>

    <p>So what I do after I process the file to make sure it's valid is use ftp to move it to my holding server. Would this be a possibility to do? I think it would add a lot to the component.</p>

  12. Dec 13, 2007

    <p>I don't quite understand what you mean or where you think that a problem with the API is...</p>

    <p>Because when PHP receives a fileupload it is stored internally within the specified temporary path. <br />
    And to get it out of there you have to move it.</p>

    <p>And within the API you can see that you can specify the destination for each file with the move() method.</p>

  13. Dec 17, 2007

    <p>Hi Thomas,</p>

    <p>I like your proposal and hope it's accepted, since it seems useful and ZF needs a component like this.</p>

    <p>I'm trying to implement it as I already need it for an application, and got some questions:</p>

    <p> 1. Do you agree Marcin Lewandowski's implementation of files and options? (not talking about the code, but about the schema) I was thinking about another property for "general" options:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[protected $_options = array();]]></ac:plain-text-body></ac:macro>

    <p> 2. About the 'move' method, is it supposed to call 'isUploaded' before trying to move?</p>

    <p> 3. More about 'move'. What is the first argument used for?</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[@param String]]></ac:plain-text-body></ac:macro>

    <p>vs.</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[$files->move('C:\path\to\put\files');]]></ac:plain-text-body></ac:macro>

    <p> 4. Must the 'isUploaded' method check for restrictions? Or does it only check 'isset($_FILES<ac:link />)'?</p>

    <p> 5. What will the 'check' method do? (if you thought about it) Checking restrictions and calling the 'check function' if set? What about the callback function?</p>

    <p> 6. What about moving/copying uploaded file/s to multiple destinations? For example, you may need several copies of an image or maybe replicating the file into another server...</p>

    <p>Thank you very much!</p>

    1. Dec 17, 2007

      <blockquote><p>I like your proposal and hope it's accepted, since it seems useful and ZF needs a component like this.</p></blockquote>
      <p>Hopefully I will get response from the dev-team until new year.</p>

      <blockquote><p>I'm trying to implement it as I already need it for an application, and got some questions:</p></blockquote>
      <p>There are a few implementations out there, but non from me because I didn't want to anticipate the decision from the dev-team.</p>

      <blockquote><p>Do you agree Marcin Lewandowski's implementation of files and options? (not talking about the code, but about the schema) I was thinking about another property for "general" options:</p></blockquote>
      <p>Yes and no...<br />
      There will be an internal options array, and it will be protected.<br />
      But it will not look like Marcin's one.</p>

      <p>Keep in mind:<br />
      Options in this place will be class-wide options, and not single-file options !</p>

      <blockquote><p>About the 'move' method, is it supposed to call 'isUploaded' before trying to move?</p></blockquote>
      <p>There will be several checks before we really "move" the file.<br />
      One of it is the isUploaded method.</p>

      <blockquote><p>More about 'move'. What is the first argument used for?</p></blockquote>
      <p>You can define that only special files instead of all are moved.<br />
      And you can define a new location for these files....</p>

      <p>f.e.<br />
      // all other files are ignored or can be moved in a later move operation<br />
      $load->move(array('file1' => 'C:\mylocation\filex', 'file2' => 'C:\mylocation\filey'));<br />
      // define a new location for all files<br />
      $load->move('C:\mylocation');</p>

      <blockquote><p>Must the 'isUploaded' method check for restrictions? Or does it only check 'isset($_FILES<ac:link />)'?</p></blockquote>
      <p>isUploaded is only one of the checks which will be avaiable...<br />
      And as the name says, it does only check if the file has been completely uploaded.</p>

      <blockquote><p>What will the 'check' method do? (if you thought about it) Checking restrictions and calling the 'check function' if set? What about the callback function?</p></blockquote>
      <p>It adds common checks like filesize, extension, and so on...<br />
      And gives the ability to work as callback to own functions which check or even change content of uploaded files.</p>

      <p>Until now I am not sure if I will add several functions one for each check or if I collect them together and run them through options.</p>

      <blockquote><p>What about moving/copying uploaded file/s to multiple destinations? For example, you may need several copies of an image or maybe replicating the file into another server...</p></blockquote>
      <p>See move()...<br />
      How the method works depends on the set options.</p>

      <p>Just keep in mind that the real implementation can be different from what you think, and you may need to adopt your code afterwards.</p>

      <p>Greetings<br />
      Thomas<br />
      I18N Team Leader</p>

      1. Dec 17, 2007

        <p>Thank you, Thomas.</p>

        <p>About the first argument of 'move', will it be possible to be called like this?</p>

        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[$load->move('file1');]]></ac:plain-text-body></ac:macro>

        <p>I mean, destination will be taken from the options.</p>

        1. Dec 17, 2007

          <p>Only if 'file1' is a downloaded file or a identifier.<br />
          Otherwise it would be treated as new target.</p>

          <p>Maybe switchable through generic options.</p>

  14. Dec 17, 2007

    fc

    <p>Hi Thomas,</p>

    <p>I like the API and I think the framework needs this class. The API is simple and consistent with other classes. It would nice if you could specify a protocol, and allow that object to handle the moving of the file. Because users might need to upload files using http (from local drive to server 1) or using ftp (from server 1 to server 2). </p>

    <p>Something like this for example:</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    Zend/
    Upload/
    Protocol/
    Abstract.php
    Exception.php
    Ftp.php
    Http.php
    Abstract.php
    Exception.php
    Document.php
    Image.php
    Video.php
    ]]></ac:plain-text-body></ac:macro>

    <p>In the example below $upload->file holds the protocol object and handles the adding and copying of the files.</p>

    <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
    $upload = new Zend_Upload_Document();
    $upload->setProtocol(new Zend_Upload_Protocol_Ftp());
    $upload->setMaxSize(60000);
    $upload->setFileType('pdf', 'doc'); // must be a mime type
    $upload->file->add('document1', array('source' => '\remote\documents', 'destination' => '\local\documents'));
    $upload->file->add('*', array('source' => '\remote\documents', 'destination => '\local\documents'));
    try {
    $upload->file->move();
    } catch (Zend_Upload_File_Exception $e) {
    // Files not uploaded or other problems
    }
    ]]></ac:plain-text-body></ac:macro>

    1. Dec 17, 2007

      fc

      <p>So if the protocol object handles the moving of the file, you can pass a directory or a connection array as parameter, eg:</p>

      <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
      // ftp object
      try {
      $upload->file->move($server, $user, $pass);
      } catch (Zend_Upload_File_Exception $e) {
      // Files not uploaded or other problems
      }

      // http object
      try {
      $upload->file->move($path);
      } catch (Zend_Upload_File_Exception $e) {
      // Files not uploaded or other problems
      }
      ]]></ac:plain-text-body></ac:macro>

      1. Dec 18, 2007

        <p>See my generic reply...</p>

        <p>Related to your testcode I see some problems which I would not solve like you:</p>

        <ul>
        <li>A downloadclass for each mime type - too complicated</li>
        <li>Set the protocol by initiating new class - too complicated</li>
        <li>File adding / source - destination - has to be simplified</li>
        <li>Move with ftp connection settings - problematic, only one server allowed</li>
        </ul>

        <p>My implementation will add more usability and would be simpler in it's handling.</p>

  15. Dec 18, 2007

    <p>It would be no problem also to support other mechanism than HTTP.<br />
    HTTP, FTP, FILE, SOCKET,... whatever.</p>

    <p>BUT:<br />
    I was told that Zend_Upload is not a proper name so I had to rename it to Zend_Http_Upload.<br />
    This does also mean that in this case other protocols are not supported.</p>

    <p>IF we allow also to support other transport machanism, we MUST rename it back to Zend_Upload as I proposed original.</p>

    <p>It would be great if we could add a generic uploader class, not only supporting HTTP but also other mechanism. But the general decision is on the dev-team, and I did not hear anything since several months.</p>

    1. Dec 18, 2007

      fc

      <p>Yes, I agree. If it's just for HTTP uploads, then Zend_Http_Upload is fine. And what about having specific methods based on the file type, for example:</p>

      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      Zend/
      Http/
      Upload/
      Abstract.php
      Document.php
      Exception.php
      Image.php
      Video.php
      ...
      ]]></ac:plain-text-body></ac:macro>

      <p>That way, you could add a _convertLineBreaks() method to Zend_Http_Upload_Document, in case you want to convert Mac and/or PC line breaks to UNIX, or any other method specific to the file type that the user is uploading.</p>

      <p>From the usability point of view, like I said before, your API is simple and easy-to-use. And that's always a plus.</p>

      1. Dec 18, 2007

        <p>Basically this is a decision of the community.<br />
        If there is a need for other protocols, I could also implement Zend_Upload.</p>

        <p>We will clearify this in the next days.</p>

        <p>Related to Document/Image and so on...<br />
        First: This is no good seperation, because there are several document types out there and each one has to be handled different. This should depend on the mime typ or a user-selection.</p>

        <p>Second: As I wrote in a comment before it is no problem to have own checks implemented. A check does not only mean to proove something, it could also mean to change something. So maybe the name "check" is not the right, but the mechanism of a self defined callback function should be clear.</p>

        <p>Third: I am not so sure if we should implement file-changing functionality within an uploader class. Why should Zend_Upload change the content, for example strip the first three lines, and store the file elsewhere and say "it's uploaded"... </p>

        <p>Of course it sounds a good idea, and it's already been discussed in the past.</p>

        <p>Still there is no solution:<br />
        Pro: New amazing functionality<br />
        Con: No one would expect "upload" to change content</p>

        1. Dec 18, 2007

          fc

          <ac:macro ac:name="unmigrated-wiki-markup"><ac:plain-text-body><![CDATA[Hi Thomas, yes, good point.

          About the Document/Image/Video separation. Is more like a grouping of mime-types. Yes, basically you are separating them into groups. Well, at least that's how I'm doing it. Each group defines its mime-types and adds its own options based on that. For example:

          All the generic options are in Zend_Http_Upload_Abstract, and the mime-type specific options in Zend_Http_Upload_

          Unknown macro: {type}

          .

          I'm not saying that this is right or wrong, I'm just brainstorming some ideas.

          ]]></ac:plain-text-body></ac:macro>

          1. Dec 19, 2007

            fc

            <p>Other thoughts on using classes to group type of files:</p>

            <p>1. addFile($file, array $options = array()) can be an abstract method inside Zend_Http_Upload_Abstract, this will allow other subclasses add its own options and methods.</p>

            <p>2. The name Zend_Http_Upload_Image, for example, improves usability and simplifies the interpretation of the class managing the upload. A user knows what type of files are being uploaded by looking at the API (if the class injects the dependency), or by looking at the code itself.</p>

            <p>3. The convertLineBreaks() was just an example, what if the developer wants to add a method to deal with a specific mime-type, is he/she going to add it to is not Zend_Http_Upload or Zend_Http_Upload_Abstract? It's much better if it's added to a subclass.</p>

            <p>3 points to consider.</p>

            1. Dec 19, 2007

              <p>These are detailed which I don't want to discuss in detail.<br />
              As long as there is no decission about the supported protocol this is useless in my eyes.</p>

              <p>A user should never add functions to a framework class. This is a useless discussion. There are standardized framework wide ways which will be implemented.</p>

              1. Dec 19, 2007

                fc

                <p>Every comment, idea and opinion is always useful, believe me.</p>

          2. Dec 19, 2007

            <p>One class for each mime-type is unpractical as mentioned before.<br />
            This will be implemented in another way.</p>

  16. Dec 19, 2007

    <p>Why do you have a <code>move()</code> method?</p>

    <p>The name 'move' might be confusing for people who don't know how PHP's builtin file upload works. And it makes it look like you're just wrapping the precedure of the lower level interface.</p>

    <p>Why not call it <code>accept()</code>?</p>

    1. Dec 19, 2007

      <p>Because move() is able to do exactly that...<br />
      It is able to move the file elsewhere... or even duplicate it and move it to two locations.</p>

      <p>Therefor accept() would not be the right name.</p>

      1. Dec 19, 2007

        <p>Thomas,</p>

        <p>The user doesn't need to know anything about moving files. The whole idea of moving files comes from the <em>procedure</em> surrounding using <code>$_FILES</code>. So you're just wrapping a procedure which does not take advantage of OOP at all. You're excluding a lot of useful subclassing scenarios.</p>

        <p>Along those lines, I also agree with Matthew that the concept behind this class is files and not something specific to the HTTP protocol or the act of uploading. Therefore the class should probably be <code>Zend_File_Something</code> and not <code>Zend_Http_Something</code> or <code>Zend_Upload_Something</code>. The focus is on files. Therefore, if the focus is on files, then <code>move()</code> <em>does</em> make sense. But I still something more abstract like <code>processFiles()</code> or <code>accept()</code> would be better. A lot more can happen in <code>accept()</code> like validation, filtering the filename, etc than just moving the file. And who's to say you're really going to move the file at all - maybe the file is just processed and discarded.</p>

        <p>For example (just brainstorming here) you could have <code>accept()</code> call <code>validate()</code> and then maybe <code>filterFilename()</code> and then <code>move()</code>. That way someone can subclass and provide their own move (e.g. FTP the files to a remote server), do their own filename mangling, etc.</p>

        <p>I don't see you putting OOP to work. You're just wrapping an existing procedure.</p>

        <p>Mike</p>

        1. Dec 19, 2007

          <p>So, just because I did not write out the filter, validator and maybe protocol subclasses you say that this proposal is useless ?<br />
          And just because the code is not working you think that it would not have advantages for the user ?</p>

          <p>Sorry, but this is nonsense... I saw much people coding such a class and I was told from several other people that such a functionality is a must for this framework.</p>

          <p>Of course I can also cancel this whole proposal, and people would still be frustrated that there is no standardised way and they would have to code their own class as before.</p>

          1. Dec 19, 2007

            <p>Thomas,</p>

            <p>I'm sorry you're upset by my criticism. I appreciate the time you're taking to work on this. If your component is accepted (and FYI it probably will regardless of what I say) I'll probably use it on my current project.</p>

            <p>However, this is not a back-slapping club. You might find that some people don't agree with you about everything. When I submitted my auth adapter proposal it got knocked around pretty good. But I didn't even <em>consider</em> getting upset. I expected it. In fact, they were right and I completely re-wrote the whole thing.</p>

            <p>I think you're overreacting a little. Don't get bent. It's nothing personal. Be happy. This should be fun.</p>

            <p>Mike</p>

            1. Dec 19, 2007

              <p>Punch - Knock out <ac:emoticon ac:name="wink" /></p>

              <p>If you're using my class I got you on my side <ac:emoticon ac:name="smile" /></p>

              <p>Sometimes I may be react a little bit loud, but if you see what I've integrated into the framework (Zend_Currency, Zend_Date, Zend_Locale, Zend_Measure, Zend_Translate, Zend_TimeSync) you will mention that I am having fun, otherwise I would not do it.</p>

              <p>I think the new API will be more what you've expected... I just added it.</p>

  17. Dec 19, 2007

    <p>Is there any way to override how the filename is filtered?</p>

    <p>Perhaps you should have a <code>filterFilename()</code> method? It could have a default behavior but also allow a subclass to redefine it's bahavior. For example, files may be stored on the filesystem by MD5 hash whereas the completely unfiltered name is stored in a database. That guarantees that no funky characters can obstruct any code that might operate on those files.</p>

    <p>Or perhaps a callback would be better?</p>

    1. Dec 19, 2007

      <p>As already said several times in the past...<br />
      There is a callback implemented. It's not called filterFilename() it's called setCheck().</p>

      1. Dec 19, 2007

        <blockquote>
        <p>There is a callback implemented. It's not called filterFilename() it's called setCheck().</p></blockquote>

        <p>Ah, ok. It wasn't clear to me how setCheck could be used to change the filename.</p>

  18. Dec 19, 2007

    <p>Hi Thomas,</p>

    <p>1. Looking at it again, I want to make sure that people aren't misled. This isn't a class for uploading anything; there's no <code>upload()</code> method. It's for <em>handling</em> uploaded files. Therefore, <code><strong>Zend_File_UploadHandler</strong></code> seems like the best name. Whether it's HTTP or FTP is irrelevant to the functionality, right?</p>

    <p>2. It needs an <code>addFileType()</code> method.</p>

    <p>3. <code>setCheck()</code> would be more in line with ZF terminology as <code>setValidator()</code>. Similarly, <code>check()</code> would then be <code>validate()</code>.</p>

    <p>Otherwise, looks good.</p>

    1. Dec 19, 2007

      fc

      <p>I agree with Matt, Zend_File is where you'd expect to find it. I'm not 100% sure about mixing all those classes: CookieJar.php, Cookie.php, Response.php and Upload.php in the same directory. It's confusing. And like Matt said, I'm not sure about Zend_Upload either, it's a symbolic name, but doesn't represent the purpose of the component.</p>

      1. Dec 19, 2007

        <p>We already changed the name two times in the past.<br />
        We should come to an conclusion related to the naming.</p>

        <p>Zend_Upload<br />
        Zend_File_Upload<br />
        Zend_File_Uploader<br />
        Zend_Http_Upload<br />
        Zend_Http_Uploader<br />
        ...</p>

        <p>Zend_File_UploadHandler... I don't know...</p>

        <p>Btw: File would us not be related to Http, so we could also add other protocols like Ftp for example.<br />
        We could also add functionality for creating the proper form elements. A related View Helper or something. They could work closed together.</p>

        1. Dec 19, 2007

          <p>I guess I'm not sure how this directly interacts with HTTP or FTP. It seems like it just picks up when whatever transfer method was used is complete. Can you explain a bit how you see this tying into those? Even if that's the case, it seems like it might be something where it would rely on <code>Zend_Http</code> and an inevitable <code>Zend_Ftp</code> class.</p>

          <p>"Zend_File_UploadHandler" is somewhat unwieldy, but it's the most accurate description of its purpose.</p>

          <blockquote>
          <p>Btw: What would a upload() function do ? Maybe we can add such functionality if it's API conform ?</p></blockquote>

          <p>That's exactly my point: there's nothing for that function to do because this class is not handling file uploads, it's handling what happens after the file is transferred from a client to a server.</p>

          1. Dec 20, 2007

            <p>I agree with Matthew, my vote for "Zend_File_UploadHandler"</p>

          2. Dec 20, 2007

            <p>This is only true for HTTP POST, but not for FTP nor for HTTP PUT.</p>

            <p>Within FTP you are giving the connection details (site, user, pwd) and the class fetches the files you are uploading to it from there.</p>

            <p>And also when you are loking at HTTP PUT, it's not the case that the files are already transfered... the class has to handle this.</p>

    2. Dec 19, 2007

      <p>1. I just remember your second reply to this proposal...</p>
      <ul>
      <li>I anticipate other Zend_File-related classes</li>
      </ul>

      <p>And in my opinion <em>Zend_File_UploadHandler</em> is a little bit unhandy in it's naming...<br />
      Btw: What would a <em>upload()</em> function do ? Maybe we can add such functionality if it's API conform ?</p>

      <p>2. Of course you're right... there are several other functionalities which will need additional methods or subclasses like the standard file validators.</p>

      <p>3. Good point with validator.<br />
      I am not full closed with the API naming... the method names are not fixed and I think they will slightly change if needed when I implement it. There will be a amount of time where we are able to fix this...</p>

      <p>To be sure... this class will not be implemented within the next release... it will stay in the incubator until we cleared all things which will cost us several weeks.<br />
      As always I am open to any idea which makes sense.</p>

  19. Dec 19, 2007

    fc

    <p>I think this class should be top priority. I mean, this is something we all use on a daily basis. And the functionality of uploading files is a standard requirement in almost every project.</p>

    <p>You have a solid API, so it would be nice if this class is given top priority, so you can focus 100% on developing it.</p>

    1. Dec 19, 2007

      <p>Not all people are thinking this way.</p>

      <p>Maybe that's the reason why, until now, this proposal was not read, commented and accepted.</p>

      <p>I will change the API as discussed before. Some things I had already in mind, but I was too lazy to write down the whole thing. Give me 1-2 days to change the API and then we can go further...</p>

      <p>I will send an notification when I've finished the rework.</p>

      1. Dec 19, 2007

        fc

        <p>Nice one Thomas (that was quick), I'll take this new API as your Christmas present. Looks great <ac:emoticon ac:name="smile" /></p>

      2. Dec 20, 2007

        <p>Thomas, the reason you're getting so much push-back and confusion about this proposal is because it's not clear what you intend to do with it.</p>

        <p>Why don't you flesh out your protocol adapters and show some use cases of how you intend to use them? Until then, I don't see any reason for them to exist over a separate <code>Zend_Ftp</code> class with its own <code>Zend_Ftp_Client</code>, etc. I also can't tell if the class should be called <code>Zend_File_Uploader</code> (with an -er) or <code>Zend_File_UploadHandler</code>.</p>

  20. Dec 22, 2007

    <p>Okay, so now we've got a better idea of what you intend for the class.</p>

    <p>This class understands HTTP POST and PUT requests. The client is sending a file to the server, and the server (via this class) is handling the file--in which case, I think <code>Zend_File_UploadHandler</code> is the most accurate name for the class, because it leaves little room for confusion. It's <em>handling</em> uploaded files, not doing the uploading itself; the client and the web server do that.</p>

    <p>But then there's FTP in the last use case, and you're providing connection information. Huh? In this case, either you mean:</p>

    <p>a) The server is acting as a client and sending files to a remote server (in which case, it is <em>uploading</em> files, not handling uploaded files), or<br />
    b) The server is connecting to a remote server and initiating a request to receive files (in which case, it is <em>downloading</em> files)</p>

    <p>Do you see what I'm getting at? In both cases, the function of the class is in question because it's doing two completely different things. If you're wanting a class to do both uploading and downloading, you might call it <code>Zend_File_Transfer</code>. Build it on <code>Zend_Http</code> and coerce someone to create <code>Zend_Ftp</code>. You'd probably want your methods named things like <code>send()</code> and <code>receive()</code> in that case.</p>

    1. Dec 23, 2007

      <p>For HTTP PUT you have to do the downloading... the Client and the Web server do not download the files. It's quite the same as FTP... you just don't have to give a connection information.</p>

      <p>I think it's a question of direction...<br />
      UPLOAD means in my eyes that you want to GET files onto your server from the client. Direction is Client to Server...</p>

      <p>DOWNLOAD means in my eyes that you want to send files from your server to the client.<br />
      Direction is Server to Client...<br />
      This is a own proposal, where I want to add wrapper technology so the client does not know where the file originally was located for example.</p>

      <p>It's always the point of view. This terms are normally seen from the client, even if the server act's on them. From the server's view all is switched of course.</p>

      <p>We could also integrate both ways into one class, Downloading and Uploading, and create a Zend_File_Transfer. But I don't know if that is wished and until now I didn't have thought of pro's and con's of this. Also if I would wait for someone creating Zend_Ftp I would be waiting forever as with the environment defaults for ZF which I had integrated into Zend_Locale and the other propsal was not done. I would not want to do this once more as it's irritating to the user.</p>

      <p>So the general question now is:<br />
      Do we want to have a generic class handling both, upload and download or do we need/want to seperate them.</p>

      <p>Having both in one class would of course have impact on the API but on the other hand several methods could be used together which we would benefit from.</p>

  21. Dec 24, 2007

    fc

    <p>Hey Thomas, it's recommended not to use method names like process(), they are to generic.</p>

    <p>Here are some naming guidelines from Jeff Moore...</p>

    <blockquote>
    <ul>
    <li>Keep names pronounceable.</li>
    <li>Abbreviate consistently. Don't abbreviate to save only one character.</li>
    <li>8 to 20 characters is best. Global and rarely used names should be longer.</li>
    <li>avoid names with similar meanings, that sound similar, that are different by only one or two characters, that use numerals, or are intentionally misspelled to be shorter. (Hilite vs. Hilight)</li>
    <li>Use opposites. (show & hide, open & close, insert & delete)</li>
    <li>A variable or type name should refer to a real world problem rather than a programming language solution, should fully and accurately describe what the variable represents and should express what, not how.</li>
    <li>Put computed qualifiers at the end of a variable name. (Total, Sum, Count)</li>
    <li>Use meaningful control variable names (not i, j, or k) if the function is more than a couple lines long or the loop is nested.</li>
    <li>Use meaningful names for temporary variables (SalesTotal instead of nTemp).</li>
    <li>Boolean variable names should imply true or false. Avoid using not in the variable name. Prefix with is or has.</li>
    <li>Use strong verbs in function names. Functions should describe their result. The name should describe everything the routine does. Consider breaking up the routine if this is not possible.</li>
    <li>Avoid generic or wishy-washy verbs in function names (handle or process).</li>
    </ul>
    </blockquote>

    1. Dec 24, 2007

      fc

      <p>Also, shouldn't Zend_File_Uploader_Protocol be renamed to Zend_File_Uploader_Protocol_Abstract? If I'm not wrong, interfaces ended with *_Interface and abstract classes with *_Abstract in ZF.</p>

      <p>I still think this class should be top priority, I know that the dev-team is prioritizing Zend_Service_* components, but a lot of developers out there keep asking how come ZF doesn't ship with the basic components for web development, such as Zend_File_Uploader, Zend_File_Utility, Zend_Image and Zend_Ftp.</p>

      1. Dec 24, 2007

        <p>There is no guideline for Abstract within ZF.<br />
        This is only true for Interfaces.</p>

        <p>Also, what you see within this proposal is not the code but only a visual interface for how the implementation should work. I am sure it will change a little bit through the implementation itself.</p>

        1. Dec 24, 2007

          <p>Re: naming abstract classes "Abstract"</p>

          <p>Maybe not, but it's pretty standard practice, right?</p>

    2. Dec 24, 2007

      <p>I don't know Jeff Moore...<br />
      Actually the naming guidelines do not recomment the above rules nor have I read them before within the ZF.</p>

      <p>And if all I am not allowed to use any name which should I use then instead ?<br />
      upload - not allowed<br />
      process - not allowed<br />
      move - not allowed<br />
      download - not allowed<br />
      start - not allowed<br />
      go - not allowed</p>

      <p>I really don't know any name to use instead...<br />
      Also to mention that the API is not fleshed in stone. It will change a little bit when we realize the implementation.<br />
      So the only benefit of having all negotated is that this class will not be accepted <ac:emoticon ac:name="wink" /></p>

  22. Dec 26, 2007

    <p>Just a word about security upload rules throught HTTP POST enctyped as multipart/form-data, anyone should read this very interesting document : <a class="external-link" href="http://www.scanit.be/uploads/php-file-upload.pdf">http://www.scanit.be/uploads/php-file-upload.pdf</a></p>

    <p>Ilia Alshanetsky also demonstrates others methods to taint all the $_FILES array in the "PHPArchitect's Guide to PHP Security" book.</p>

    <p> PECL fileinfo extension is to be a good native C solution : it should be merged in PHP 5.3's core</p>

    1. Dec 26, 2007

      <p>So you propose to use the PECL fileinfo extension instead of creating a generic standardized uploader class...</p>

      <p>2 Negs:<br />
      First: The minimum requirements are 5.1.4.<br />
      Second: Until now the extension is not in the core and until then everyone would have to cook his own soup as today.</p>

      <p>Target of this proposal is to give a generic and standard way of file up-/downloading.<br />
      And I think most of ZF-users would not buy this book you mentioned just for downloading their files to make their own class.</p>

  23. Jan 19, 2008

    <p>Hy interested ones,</p>

    <p>I reworked the API as requested and changed the name to Zend_File_Transfer.<br />
    Generally the class can now handle</p>
    <ul>
    <li>File uploads</li>
    <li>File downloads</li>
    <li>File validations</li>
    <li>File filters, to change the content</li>
    <li>Work with different adapters like http, webdav or ajax. Could be extended in future</li>
    </ul>

    <p>Waiting for approvment or another change request...</p>

  24. Jan 25, 2008

    <p>If this proposal includes file downloads it should cover http forced downloads, which allow a PHP script to send a file without revealing its actual directory and allows placing files in directories that are not directly accessible. This allows sending file based on permissions and other security benefits like preventing direct linking and so forth.<br />
    Documentation on performing this caveat is rather sparse on the web, but it basically involves sending the correct http headers.</p>

    <p>Something like:</p>

    <p>if(is_file($file)){<br />
    header("Pragma: public");<br />
    header("Expires: 0");<br />
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");<br />
    header("Cache-Control: private",false); <br />
    header("Content-type: application/force-download");<br />
    header("Content-Transfer-Encoding: Binary");<br />
    header("Content-length: ".filesize($file));<br />
    header("Content-disposition: attachment; filename=\"".basename($file)."\"");<br />
    readfile("$file");<br />
    }</p>

    1. Jan 26, 2008

      <p>Please read the proposal carefully...</p>

      <p>This is already covered as downloading files works ALWAYS as Wrapper describes as <strong>Wrapper for Downloads</strong>. This means files must only be accessable by the php process but not to the public.</p>

  25. Jan 25, 2008

    <p>Due to my own stupidity I forgot to use the wiki tags.</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    if(is_file($file)){
    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private",false);
    header("Content-type: application/force-download");
    header("Content-Transfer-Encoding: Binary");
    header("Content-length: ".filesize($file));
    header("Content-disposition: attachment; filename=\"".basename($file)."\"");
    readfile("$file");
    }
    ]]></ac:plain-text-body></ac:macro>

    1. Jan 26, 2008

      <p>Too complicated for normal users...</p>

      <p>We will integrate a way to use a default set of headers and/or to set them via defined methods. Users should never set headers manually because most users don't know which header to set for downloads so they work properly.</p>

      <p>We should make this as simple as possible.</p>

      1. Jan 26, 2008

        <p>Of course not, you missed my point - This type of implementation should be abstracted by the File_Transfer class so normal users can have this functionality without knowing the specifics. I was just suggesting an implementation of the forced download method.</p>

        <p>I didn't see such functionality in the class skeletons provided, and their documentation isn't overly descriptive... I didn't understand your reference to Wrapper, and a text search only revealed an instance of the wording in one the use cases. </p>

        1. Jan 26, 2008

          <blockquote><p>|Too complicated for normal users...</p></blockquote>
          <blockquote><p>Of course not</p></blockquote>

          <p>Sorry, but in my opinion many users dont know the exact headers to use... so your code is too complicated for many users.</p>

          <blockquote><p>This type of implementation should be abstracted by the File_Transfer class</p></blockquote>

          <p>It will not be abstracted by the transfer class itself, but within the specific adapter. Otherwise we could not have it seperated by protocol.</p>

          <blockquote><p>I was just suggesting an implementation of the forced download method.</p></blockquote>
          <p>How could we implement this simpler as with only one send() command ??</p>

          <blockquote><p>I didn't see such functionality in the class skeletons provided</p></blockquote>
          <p>A small description in the usecase for FTP download... would be implemented quite the same with http... only headers would be set automatically, the usecase it not right at this point.</p>

          <p>A wrapper is a code which hides what is done behind it... the wrapper has access to the file, he sends it to the user... this means the wrapper acts as download portal, and the users must not have access to the file he wants to download. This way you can also verify if the user has the right for this file by acl or a similar solution.</p>

          <p>Anyhow... if I have to document all things which can be done with this class we will have it ready for ZF 4.0 and this proposal will have 20 pages useless documentation.<br />
          There is no proposal where ALL things are written. I waited now almost one year and now I am near at forgetting this proposal and delete it because until now I only got negative responses and no positive ones. <ac:emoticon ac:name="sad" /> That's really frustrating.</p>

          1. Jan 27, 2008

            <p>Hi Thomas,</p>

            <p>it would be really pity I this proposal should be thrown out. It's quite surprising, but for such a common task as file uploads there's no PHP 5 class with all the features that Your proposal has and with fine and consistent API.</p>

            <p>I watch this proposal from time to time and l like the way it goes to (from common file HTTP upload/download class to generalized one with different adapters, AJAX support, etc.). It's lots of good work done on it, many thanks for Your effort (not only on this proposal but for all Your great work for ZF). Sooner or later, ZF will need such component, so it's quite surprising that users pay so little attention to this proposal.</p>

            <p>Unfortunatelly, for next about two weeks I have no time to read this proposal from top to down with all the comments <ac:emoticon ac:name="sad" />. Just after a quick view, it looks good for me, I'd just like to ask one thing - how will be the MIME type check implemented then? In discussion above You mentioned that using PECL FileInfo extension is not a good idea, and for reasons You named I guess that using of PEAR Mime_Type is not the way to go too.. </p>

            1. Jan 27, 2008

              <p>In general each component should look not to depend on specific extensions. Most users are not able to add extension within their hosts because of restrictions.</p>

              <p>So the way to go is to use the available extensions in a sort of fallback.<br />
              We will define a top - down search and use what's found...</p>

              <p>Could be Pecl Mime / Pecl Fileinfo / Pear Mime / Pear FileInfo / ZF Mime...<br />
              Something like that. Note that not all of this components exist, but you should get a feeling of what I meant.</p>

              <p>Related to past responses:<br />
              It's also a thing of security... relying only on the extension of a file is a security-hole. That's why I said that it's not a good idea in past.</p>

              1. Jan 28, 2008

                <p>I did some work on a Zend_Mime_Magic component. It's in the archived proposals right now (archived because I bought a house and am fixing it up, but am almost done). However the coding is mostly done and I just have to get around to resurrecting it and finishing the unit tests.</p>

                <p>It has a native magic file parser but can optionally use the Fileinfo component instead.</p>

                1. Jan 28, 2008

                  <p>I know Matthew... otherwise I would not have mentioned it.<br />
                  But all depends on the acceptance of this proposal.</p>

                  <p>What will be used will be decided later on... because there are also some other extensions which should/could be loosly coupled with Zend_File_Translate. Based on which extension is available the related functions can be used or are not active.</p>

          2. Jan 27, 2008

            <p>I'm not sure why you insist on misquoting me - This functionality IS too complicated for most users to perform manually, they obviously would NOT know the specific headers, therefor it should be handled for them by framework. I didn't say put it directly in the class, it is hard to ascertain the exact workings of your class from the class skeleton - If you say this kind of code belongs in wrapper for download, I had no qualms with that.</p>

            <p>I'm sorry that you experienced negative feedback in the past, I was merely trying to contribute important functionality in my opinion, one that I would have liked available if such a class was to be included in the ZF.</p>

            <p>Peace</p>

            1. Jan 27, 2008

              <p>I'm not native english... sorry if I misunderstood you.</p>

              <p>So we both have the same opinion that users should not know the exact working of wrapper or download headers. And that this component must handle this in a convinient and simple way.</p>

              <p>You all should also keep in mind that this is only a proposal, not a working class where the code has been stripped off... it's the nature of such things that they will grow while coding and that they will be available several weeks in the incubator for improvments or feature enhancements. Having 30 people said that this or this feature must be integrated is on one side nice but on the other side it also means that the class itself is delayed... in the case of this proposal delayed one year.</p>

              <p>Related to feedback: It was also said from the devteam in past that this class has no benefits over standard download mechanism of PHP. So I'm not even sure if they want to have such functionality integrated. They are the one to get on our side, not me <ac:emoticon ac:name="wink" /></p>

  26. Jan 30, 2008

    <p>Hi,</p>

    <p>I think defining multiple file types should be made in a different way, because in my opinion something like 'jpg|pdf' isn't very cute.</p>

    <p>Maybe this should be made trough some classes or at least a multi dimensional array.</p>

    <p>Maybe it should be also be possible to exclude just some kind of files and allowing all others.</p>

    1. Jan 30, 2008

      <p>As stated within the proposal there will be "Validators".</p>

      <p>And they are extendable... this means you can also write your own or extend existing validators to fit your needs.</p>

      <p>One of these validators will be used to validate if a fileextension fit's or does not... another could be to exclude files or extensions. This will grow in future depending on needs and usefullness.</p>

      <p>But the whole proposal is not accepted for now and I will not make implementation details without the basics accepted.</p>

  27. Jan 31, 2008

    <p>There's "too many things" going on with this proposal. </p>

    <p>a) There should be a Zend_File_Collection / or Zend_Files which implements a Collection</p>

    <p>$col = new Zend_Files;<br />
    $col->addFile('foo.img');<br />
    $col->filter(...);<br />
    $col->etc....</p>

    <p>b) You can then upload this collection of files (through some adapter)</p>

    <p>$tr = new Zend_File_Transfer; // Uses some default adapter<br />
    $tr->setTransport('WEBDAV', array(..options..));<br />
    $tr->add('foo.txt', $col); // Can add a single file or collection of files...<br />
    $tr->put('somePath/');</p>

    <p>...</p>

    <p>The filtering and validation <strong>should</strong> exist with the 'collection of data' - ideally similar to java or .net</p>

    1. Jan 31, 2008

      <blockquote>
      <p>There's "too many things" going on with this proposal. </p></blockquote>

      <p>To provide a generic way for transferring files there is much work to do...<br />
      So what's your clue ? To erase the proposal because it aims to be too generic ?</p>

      <blockquote>
      <p>a) There should be a Zend_File_Collection / or Zend_Files which implements a Collection<br />
      b) You can then upload this collection of files (through some adapter)</p></blockquote>

      <p>This is not part of this proposal and will not be implemented... but it could be a feature enhencement or when it really has to be a new class then it must be a new proposal.</p>

      <blockquote>
      <p>ideally similar to java or .net</p></blockquote>

      <p>We are not building java or net... we are collecting ideas from all over and try to make it simpler and possibly better.</p>

  28. Mar 05, 2008

    <p>Hi Thomas,</p>

    <p>Could you please tell me what the current status of this class is?<br />
    I thought I could locate it in the Incubator, but I haven't found it.</p>

    <p>I second the opinion that this class should get a higher priority at the "decision board" <ac:emoticon ac:name="wink" /></p>

    <p>Best regards,</p>

    <p>Patrick</p>

    1. Mar 05, 2008

      <p>As you can see this proposal is still under review by the dev team.<br />
      It is not allowed to commit not accepted classes in the incubator.</p>

      <p>As long as there is no decision that the API is ok, or that there are changes necessary to the API recommended by the dev team, I am not able to do any work. It would not be a good decision to do some coding and then throw all work away because the API is not accepted.</p>

      <p>So we both have to wait some more...<br />
      I am sure that with the release of 1.5 (or the next RC) the dev team has little more time to do futher reviews as for now there are much proposals which have to be reviewed in the queue.</p>

      <p>Greetings<br />
      Thomas, I18N Team Leader</p>

    2. Apr 15, 2008

      <p>I also think the class should be included rapidly. Imho Zend_Form will be much useful if it will be possible to manage file upload at the same way as textareas and inputs, without third party classes.</p>

  29. Mar 16, 2008

    <p>Hi Thomas,</p>

    <p>Thanks for putting together this proposal. I think this is a pretty useful component, and it's looking great so far!</p>

    <p>I'd like to ask whether it's planned to support files array notation in this component? <ac:emoticon ac:name="smile" /></p>

    <p>Zend_Form supports array notation, so I'd imagine that if it would rely on Zend_File_Transfer for file uploading (something I believe Zend_Form's author is planning) then support for array notation in Zend_File_Transfer would be a must. Also, unfortunately, PHP's array notation for $_FILES is a bit weird (different than that of $_POST at least. Ref: <a class="external-link" href="http://www.php.net/manual/en/features.file-upload.multiple.php">http://www.php.net/manual/en/features.file-upload.multiple.php</a>), so it would make for a great potential area to improve.</p>

    <p>Thanks, Thomas!</p>

    <p>Kind Regards,</p>

    1. Mar 16, 2008

      <p>Yes, Zend_Form will be coupled with Zend_File_Transfer for file uploads and his name is Matthew <ac:emoticon ac:name="wink" /></p>

      <p>And yes, array notation will be supported. As you see, you can add files with the addFiles method which takes an array of any notation. It will support $_FILES, $_POST of defined structure and also sort of self defined array. And of course there will be a way of automatism, so it will handle any detected source of files automatically.</p>

      <p>Usability and Simplicity are a must criteria for me and ZF. So you can be sure that it will be improving the actual way of PHP. <ac:emoticon ac:name="smile" /></p>

  30. Jun 02, 2008

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Comments</ac:parameter><ac:rich-text-body>
    <p>The Zend Framework team approves this component for immediate development in the standard incubator, with the following suggestions:</p>

    <ul>
    <li><strong>Consider extending Zend_Form_Element.</strong> There is a lot of overlap with Zend_Form_Element, particularly in terms of using validation and filter chains and use of isValid(). Our recommendation is that it extend Zend_Form_Element; that way it can be used both standalone and as an element. A targetted Zend_Form_Element_File could simply extend it to ensure it can be found by Zend_Form automatically.</li>
    <li><strong>Ajax Uploads.</strong> These could be done via a decorator, if Zend_Form_Element is used as a base class.</li>
    <li><strong>Validators.</strong> We recommend building some file-specific validators for checking extensions, mime type, file size, upload status, etc. These could then be used for other purposes outside the Zend_File_Transfer component.</li>
    </ul>
    </ac:rich-text-body></ac:macro>

  31. Jul 26, 2008

    <p>For me the proposal code does contains too many "magic strings". Replacing them with class-constants or object would make the code more secure against programmer faults, at least when they do use an IDE.</p>

    1. Jul 26, 2008

      <p>What do you mean with "magic strings"? Actually there are no magic strings at all.<br />
      Have you looked at the actual implementation?<br />
      Have you looked in the working examples I already provided in my blog?<br />
      I would not know how to make this simpler as it's actually implemented.</p>

      <p>If you see any problems it would be better if you give a detailed description on the problems you see with the actual implementation.</p>

      1. Jul 28, 2008

        <p>This is no critics on you, it's just one thing I would do different in code so I suggested it and I might even agree if you have different opinion. But I might be a bit more specific as "magic strings" seems to be no common known concept. "magic strings" are the same thing to strings as "magic numbers" are to numberic values.</p>

        <p>"Magic Strings" are constants represented trough a string, this makes the code harder to use because the "Magic Strings" are hardly to document, a type error can happen very fast and code complition of a IDE can not help.</p>

        <p>Some Ideas how you could remove the Magic Strings from the examples above (but I know this suggestion does come very late, as the code is allready finished):</p>

        <ul>
        <li><em>$files->addValidator(new Zend_Validator_MaxSize(2000));</em> instead of <em>$files->addValidator('MaxSize', 2000);</em></li>
        <li><em>$files = new Zend_File_Transfer(Zend_File_Transfer::</em><em>WEBDAV</em><em>, array(</em><em>'user'</em><em> => </em><em>'adam'</em><em>, </em><em>'pwd'</em><em> => </em><em>'sandler'</em><em>, </em><em>'server'</em><em> => </em><em>'myserver.com'</em><em>)); </em> instead of <em>$files = new Zend_File_Transfer(</em><em>'WEBDAV'</em><em>, array(</em><em>'user'</em><em> => </em><em>'adam'</em><em>, </em><em>'pwd'</em><em> => </em><em>'sandler'</em><em>, </em><em>'server'</em><em> => </em><em>'myserver.com'</em><em>));</em> <br class="atl-forced-newline" /></li>
        </ul>

        1. Jul 28, 2008

          <p>I havn't seen this as critism, but it's always better to discuss with examples when people don't have the same motherlanguage. <ac:emoticon ac:name="wink" /></p>

          <p>What you see as "Magic String" is not implemented as you may expect.<br />
          Let's look at the validators... there are no constants or other variables declared. When you give a string, the class looks if there is a proper validator available... so if you give 'Size' it will look for 'Zend/Validate/File/Size'... if not found it will try to load Size as it is, maybe with autoloader or whatever you may have declared as include path. So to be clear... there is no constant defined. So if you try to load 'MyValidators_File_Size' it will also be loaded.</p>

          <p>You said that you want to solve this a different way... well, which way would be the right one in your eyes ?</p>

          <p>You can still initiate the validators manually your own but you will then have more overhead to do yourself. And you can use the validator class also in combination with the adapter directly. But there is no bonus with this way, except that you will have to write more...<br />
          new Zend_Validator_File_Size instead of 'Size'.</p>

          <p>Maybe you should really first take a look at the existing code.</p>

          <p>Please keep in mind that anything shown in this proposal is just a point of proove and no finished implementation. Because of this details which become clear as soon as we have working code, the end-version behaves slightly different. <ac:emoticon ac:name="smile" /></p>

          <p>I tend always to keep things as simple as possible for users. <br />
          Btw: You are declaring two different styles in your two example lines...<br />
          First you say to use class declaration... method(new class(...))... <br />
          And second you say to use class constants, which you declare are "magic strings", and which shall not be used ??? For me you negotate yourself. <ac:emoticon ac:name="smile" /></p>

          <p>So to get to the point:<br />
          Things are much simpler as you may expect... there are no "magic strings", as you declare them, implemented. You can eighter wait until the official implementation is ready to see this yourself, or look at the actual code and see yourself that all works like you wrote it should. Or you simply wait for 1.6RC2 to be available. <ac:emoticon ac:name="wink" /></p>

          1. Jul 29, 2008

            <p>Well I know that the Zend_Loader_PluginLoader is wide spread in ZF i do run over it on the MVC part serval times (I do not use Zend_DB so I do not know there).</p>

            <p>I did not find the code of Zend_File_Transfer in the svn, so I can not argue about this. If you can also give an object instead of the string that would be great. Because using the Zend namespace for your own code is somehow hacky.</p>

            <p>The thing I suggested it's a tread off between tiping more and security. In my Example you have to type more (doesn't really matter if you use an IDE) but errors will be recognized much earlier by the compiler. For me the second is much more important (as we run ZF with a big team) but I know this is not for everyone an issue. And if you look at my examples again it's just two different ways to remove magic strings. The first one overgives an object because I think it's likly that one will write a own validator, the second does use a class constant (misstippes will be also fewer with an IDE and the error will be recognized earlier) because likelyhood that you write your write own backend is much lower.</p>

            1. Jul 29, 2008

              <p>The code is currently in the incubator, and you can test it there. And yes, you can attach both actual object instances as well as utilize the plugin loader.</p>

        2. Jul 28, 2008

          <p>You need to do some reading on Zend_Loader_PluginLoader. The purpose of using short strings when passed to the validators and filters is to allow the developer the ability to define their own replacements for them. The PluginLoader will only attempt to load classes based on the prefixes registered with it – so, by default, these will only be within the standard defined validators and filters. They are not constants in any way.</p>

          <p>The PluginLoader is being used in a variety of places within ZF, including Zend_View and Zend_Form – for the exact same purpose.</p>

        3. Jul 28, 2008

          <p>This is to save on typing. Zend_Db does this as well for the same reason.</p>

  32. Jun 25, 2009

    <p>Good morning every single one!</p>

    <p>I have the need to download some files via FTP. Zend Framework offers File/Transfer/Adapter/Http which seems a bit not-working for my ftp-protocol.</p>

    <p>Since here did none post something for about one year - I want to discuss the need (at least mine) to have a ftp-adapter.</p>

    <p>I would suggest(and try) to copy the Http.php to Ftp.php and see how far I can implement a slightly more ftp-like functionality.</p>

    <p>After some quick research I figured out, that at least a function "get file listing" is not yet available in the abstract adapter - and has to be implemented "somehow" "somewehere" (in the Ftp class?)</p>

    <p>So - feel free to join the discussion about this, or if possible send me your Ftp-adapter <ac:emoticon ac:name="wink" /></p>

  33. Feb 09, 2010

    <p>It looks like this has stagnated a bit - the manual states that:</p>

    <p>Note: Limitation<br />
    The current implementation of Zend_File_Transfer is limited to HTTP Post Uploads. Other adapters supporting downloads and other protocols will be added in future releases. </p>

    <p>Is there any work on the downloader?</p>

    1. Feb 10, 2010

      <p>There were many changes and additions which are used by all elements.</p>

      <p>Additionally I worked on a PUT extension and made some pre-works and definitions for WEBDAV and FTP. But these are not official and therefor not available to public for now.</p>

      <p>Additionally Downloads can already be done (limited to http) by using Zend_Http_Client.</p>