My TinyMCE File Management : Spinoff 1 : PHP file uploads

PHP UploadsI have been writing on how to handle files for use with TinyMCE in the past (Part 1 & Part 2). Before continuing the series I feel like writing a more general post on the subject, as this will give insight in the how and why later on. Having experimented with file uploads myself in quite some (upcoming) projects I think I have created a nice insight in all the various methods, their pros and cons, etc. Hereby my quest to finding the best way of uploading files by using PHP…

Why even bother when you have those nice AJAX File Upload thingies with progress bar?

There happens to be a lot of misunderstanding about this, so let me make it clear to all: There is no such thing as an “AJAX File Upload With Progress Bar”!. The XHR Object just does not support this! The only AJAX that might ever come in these are the periodical calls to a file that returns the current size of the file that is being uploaded.

In the list of the so called “AJAX File Upload” & “Upload With Progress Bar” stuff we have:

“Upload Progress Meter” immediately falls out of the boat since it requires a patched version PHP. FileChucker also gets ditched since it’s not PHP but Perl and it’s not that easy to customize (Above that I noticed that you now have to pay for this version). Same goes for tesUpload: it’s Perl! RAD undergoes the same faith since that’s Java, leaving us only with “PHP Upload Progress” by devpro.it, but that ain’t AJAX either … it actually is a port of the ActionScript LoadVars Class. Above that I have found it buggy most of the time.

Okay, now what?

A very nice way of uploading files is through Flash. Since the release of Flash 8, the FileReference Class has been introduced which enables this all.

Pro’s to this method are:

  • Progress bar due to the onProgress Event!
  • Ability to define what types of files can be selected to upload (viz. “Pictures only”)
  • Ability to select more than one file to upload
  • Ability to upload multiple files at once
  • Ability to define how big a file is, even before it is uploaded!
  • Target of script to actually place the file can be in any language (PHP/ASP/…)
  • More in the Macromedia LiveDocs…

Above that you also benefit from the Rich flash features … if you’re tired of the lousy input[type=file] element then this is something for you: no graphical limits whatsoever!

A Real Life (TM) layout example of this could go from very normal, to the a more designed layouts, as pictured below:

PHP Uploads Flash

Problems with the Flash Method

Other than the fact that Flash 8 (not 7 nor 6, but 8!) is required there also is a problem with the onComplete Event of the FR Object: it is not able to read the result that is outputted. In a situation where you’d want to read in a generated filename of the upped file (after is has been uploaded), you won’t be able to do it unless you generate the name in flash itself (or maybe get it from a generationscript via LoadVars). The onComplete event only checks if the target of the upload has been found or not. In layman’s terms it comes down to this: either return a 404 when the file has not uploaded, or return a 200 when it has succeeded.

if ( move_uploaded_file( $_FILES['Filedata']['tmp_name'] , $uploadfile ) ) {
header('HTTP/1.1 200 OK'); // upload ok
}else{
header('HTTP/1.1 404 Not Found'); // upload not ok
}

Another issue is the fact the flash opens it’s own connection and does not take over your active session. This is obvious, yet in some situations it is not wanted. Solution to this is passing in your session params to the swf via the flashvars.

Extending the Flash Method

A recent project that has taken this method a wee bit higher is SWFUpload. SWFUpload closes the gap between Flash’ FileReference and Javascript thanks to the ExternalInterface Class. Many might think that this is revolutionary, but I’ll disappoint them when I say it has been done before (be sure to click the demo link). Coincidence or not but I myself actually was planning on writing something in the line of SWFUpload (yet I don’t think I would have come up with the SWFUpload spiffynes!)

Any non-flash method?

A method I like a lot is the usage of a hidden iframe to uploading. This method is very very very robust imo since a hit on the refresh button (F5 most likely) won’t repost the form (sidenote: after having received data via POST I always redirect to a normal page, so that the data can’t ever be retransmitted by a refresh. I have found this to be "Best Practice"). The idea behind it is very simple:

  • Upload a file through a normal HTML Form to a normal serverside script
  • Only, set the target of the form to the name of the iframe

In code, this results as this:


<!-- the form -->
<form method="post" enctype="multipart/form-data" id="uploadForm" target="uploadIFrame" action="doUpload.php">
  <input type="file" name="myFile">
  <input type="submit" value="Upload File">
</form>

<!-- the iframe -->
<iframe name="uploadIFrame"></iframe>

From within doUpload.php (nothing special about that file) you can then do whatever you want. Via the javascript “window.parent” you can then call the parent (thus the normal site) its javascript functions, handy if you were to dynamically update a list of files.

When having a listing of downloads, you could implement this like so:

  1. Clicking the Add new download link results in a Lightbox alike overlay to appear. The overlay holds the form, and a hidden iframe. The target of the form is set to that hidden iframe.
  2. When the submit button is pressed, the form is locked, and the close button of the overlay disabled.The upload is in progress to the hidden iframe.
  3. When the upload has completed the php file that handled the upload outputs some javascript that calls the window.parent.doneUpload(X); method (Where X is the unique ID assigned to the file)
  4. The doneUpload(X) function is set so to:
    • hide the overlay
    • insert the file as it should appear on the listing
    • highlight it to give visual feedback

Visually one should see this as so (screenies from a Real Life (TM) project!):

PHP Uploads iframe

As you can see a lot of stuff can be achieved with this (you have the whole DOM at your fingertips!), as long as javascript is enabled.

Wasn’t that the WordPress way you just described?

No it wasn’t. In the WordPress admin the whole file upload form is placed inside an iframe and it behaves in a normal way. See it as the iframe having the form as a child, whereas in the method described the iframe is a sibling of the form.

Any other methods worth mentionning?

More than a year a go The Stickman posted a nifty method on how to upload multiple files by using only 1 input[type=file] element. The method itself actually uses more than 1 single input[type=file] element, yet only 1 at a time is shown … therefore the name given was chosen I presume. When looking at the javascript used for this method it all becomes clear: when the input has changed its value (thus a file was chosen), it hides itself (by placing it offscreen at -1000px, a commonly used CSS practice) and inserts a new input[type=file] element together with a button to delete the hidden one.

The reason that it doesn’t just create a new element and copies the value into it is quite simple: when having an input[type=file] element one cannot simply set its value due to security reasons. Just imagine if it were possible: one could create a hidden form, set the value of the file element to any file (lets say your SAM File which "holds the user names and password hashes for every account on the local machine, or domain if it is a domain controller") and then let it automatically submit.

For this reason it isn’t possible either to combine the flash way of selecting files (multiple files, filetype filter, etc.) with the autogeneration of input files 🙂

Final thoughts

As you can see there are many possible ways to uploading files … in the suggested methods here (Flash & iFrame) each have their pros and cons:

Flash method : Pro

  • File type filter and other various checks (such as checking filesize before uploading)
  • Select multiple files at once
  • No visual limits
  • Progress bar
  • All the Flash goodness such as ExternalInterface to pass callbacks to Javascript

Flash method : Contra

  • onComplete event could have been better
  • Flash 8 required
  • Uses own connection, thus a new session

iFrame method : Pro

  • Simple (no need to learn Flash, just uses your basic XHTML knowledge)
  • Bypasses the refresh problem when file has completed uploading
  • Do whatever you want after the file has been uploaded, without refreshing the page (use window.parent from within the iframe)

iFrame method : Contra

A real winner can’t be chosen from this since it always depends on what you are building (remember: it’s not because you can that you should):

  • Tech support site where users can attach a logfile if needed : normal form will suffice
  • Image gallery webapplication where a user can upload a full photoalbum : flash method (or normal form with zip extraction at the server end)
  • SPI where one is typing a post and directly is able to upload and insert images (cfr. WordPress) : hidden iframe method, or SWFUpload

Happy coding!

Bram.

Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Join the Conversation

5 Comments

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.