ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

nGen file field + upload progress bars = :-)

October 23, 2009 7:49am

Subscribe [22]
  • #1 / Oct 23, 2009 7:49am

    rmedek

    131 posts

    So this isn’t an official write up or anything because it’s five in the morning and I am just wrapping up my day on this, but I got something working that I was excited to show off a bit and maybe in the next few days when I get a little spare time I’ll detail it all just a bit more.

    Long story short: I modified the nGen File Field extension (used with Brandon Kelly’s FieldFrame) to insert an upload progress bar, which I set up using the gist of this script and an install of uploadprogress.

    The result is visual feedback for the client who is wondering if his browser froze while he’s waiting for his 30MB file to upload.

    Anyway, here it is in low-budget glory : http://littlethinky.com/tutorials/movies/upload-file.mov

    As you can see I’m using a few other extensions, too…all in all I think it makes things a lot easier on the backend of things.

  • #2 / Oct 23, 2009 8:41am

    Ingmar

    29245 posts

    Very nice, I’d definitely like to see more details about that one ... Impressive.

  • #3 / Oct 23, 2009 8:46am

    Tomaz B.

    31 posts

    That’s great. I wanted to make a request for that some time ago. Useful for some impatient clients…

  • #4 / Oct 23, 2009 9:26am

    ender

    1644 posts

    very nice indeed, would love to hear the details.

  • #5 / Oct 23, 2009 10:44am

    Focus Lab Dev Team

    1129 posts

    You know, I’ve always wished nGen File Field came with this functionality. Well done 😊

  • #6 / Oct 23, 2009 11:04am

    moogaloo

    200 posts

    sweeeeet!

  • #7 / Oct 23, 2009 11:08am

    OutofControl

    164 posts

    This would make a few of my clients flip out. Nicely done!!!

  • #8 / Oct 23, 2009 12:12pm

    ian Pitts

    175 posts

    Oh, you really, REALLY need to give a write-up on this! This is great!

  • #9 / Oct 23, 2009 12:47pm

    Steven Grant

    894 posts

    excellent work - certainly useful for those large files like audio/movies

  • #10 / Oct 23, 2009 1:09pm

    Mark Bowen

    12637 posts

    Wow would love to see a write-up of this when you get the chance, looks really great.

    If I can ask though I’m just wondering what would happen if you say had more than one upload field? Would the progress bar concatenate the times for all the files or perhaps show each one separately?

    Best wishes,

    Mark

  • #11 / Oct 23, 2009 1:31pm

    Ryan M.

    1511 posts

    I mentioned this to Fred @nGen a while ago, but he’s a busy guy. Looks interesting.

  • #12 / Oct 23, 2009 2:32pm

    Philip Zaengle

    293 posts

    Yeah, I’d love to keep clients out of FTP…. Looking forward to hearing more.

  • #13 / Oct 23, 2009 5:12pm

    rmedek

    131 posts

    Thanks guys, glad you dig the concept. I was pretty thrilled to get it done…I’m not very skilled in this area of web design so it took the better part of three days to figure out the right combo of other people’s work. 😉

    Wow would love to see a write-up of this when you get the chance, looks really great.

    If I can ask though I’m just wondering what would happen if you say had more than one upload field? Would the progress bar concatenate the times for all the files or perhaps show each one separately?

    The PHP extension that does the processing actually looks at the total amount of data posted, not really the individual files, so the meter reports the percentage of everything on the page that’s uploading.

    You know, I’ve always wished nGen File Field came with this functionality. Well done 😊

    Me too…but in the end I think it’s be really difficult to make this a one-size-fits-all plugin, because unless you used a Flash setup to do the uploading you need to poll the server itself to get the upload progress. More on that in a bit…

  • #14 / Oct 23, 2009 6:22pm

    rmedek

    131 posts

    Okay so a little bit on how this was built…

    First of all, I am so not good at this sort of programming that I am almost 99% positive following my instructions will cause your server to implode. But maybe those of you better at this than I am can make something real out of it?

    Second of all, the internet is awesome and if it wasn’t for other people posting their solutions to problems I never would have gotten anything done.

    Third of all, I’m sorry in advance that this is so long, I didn’t really edit it and I don’t want to post it on the Wiki or a blog because I’m still not sure of the general stability and security of what is going on.

    So, the issue is file uploads — it’s a real drag uploading large files via EE (not picking on it, it just happens to be the CMS we’re all using), partly because there’s the issue of PHP memory, partly because the browsers are wacky, mostly because there’s no way to see how the upload is going, which is a Bad Experience for the client. Using FTP is an even bigger drag because we went through all these lengths to sell a magic CMS to the client and now we’re making them bust out Transmit when in their mind “YouTube and YouSendIt can do it, why can’t my site?”

    So here’s a basic list of what needed to be addressed and how I did it. By the way, I lease a server that I host most of my clients on, just for occasions like this, so addressing the PHP issues is easier for me. Your mileage may vary.

      1. get PHP happy with dealing with large files
      2. get Safari happy with dealing with large files
      3. set up the server so it can report on file progress
      4. get that file progress injected into the control panel somehow

    PHP’s issue is mostly memory, so I bumped up these figures in my php.ini file (if you’re a reseller using WHM you can also do this through the control panel):

    memory_limit = 500M
    post_max_size = 300M
    upload_max_filesize = 100M

    post_max_size needs to be bigger than upload_max_filesize, and memory_limit needs to be pretty large if you’re gonna handle anything larger than a few MBs.

    Next up, Safari sometimes hangs when trying to upload anything larger than a few hundred kB, and after a little bit of digging I found that adding

    header("connection: close");

    …to the very top of system/index.php seemed to solve that issue. I guess the deal is Safari might have issues closing the HTTP connection and adding this header to the page that processes the form helps. I’m sure there is a more elegant way of solving this but so far it doesn’t seem to bother tech support very much.

    The biggest part of the upload equation is how to poll the server to get upload progress. I used a PHP extension called uploadprogress (I got the idea from this article). There are a bunch of different options out there depending on your server set up (different PHP extensions, Apache modules, Linux patches, etc.); this was the easiest for me to set up on my server. This guy does a great job of explaining how it works.

    Finally we get the progress meter installed. I don’t know how to code extensions and all that so I piggybacked some jQuery on my install of nGen File Field. Theoretically you could add this code wherever you wanted and ideally as its own extension but for me it made sense to incorporate it into the file field.

    The way the script works is like so:

      1. insert the HTML of the progress meter
      2. insert the UPLOAD_IDENTIFIER variable uploadprogress needs
      3. call up a PHP page via ajax which will grab the current upload info
      4. report that info back to the progress meter

    Initially I rolled this code myself but I couldn’t get it to work in Safari — turns out Safari will not run ajax code after a form has been submitted (after the browser leaves a page). Eventually I found a solution online as well as a script that did most of the work; the key is to run the code from an iframe which reports back to the parent page.

    To install all this I added some new files and images to the /system/extensions/fieldtypes/ngen_file_field directory and did a little editing.

    First, I called the extra scripts I needed (ft.ngen_file_field.php):

    $this->include_css('styles/ngen_file_field.css');
    $this->include_js('scripts/jquery.livequery.js');
    $this->include_js('scripts/jquery.uuid.js');
    $this->include_js('scripts/jquery.uploadProgress.js');
    $this->include_js('scripts/jquery.ngen_file_field.js');

    uuid.js is a simple plugin to create a uuid, uploadProgress.js is the script I linked to above.

    Next up, I added the PHP page that would gather the upload info (uploadprogress.php):

    <?php
        header("Cache-Control: no-cache, must-revalidate");
        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    
        if (@$_GET['id']) {
            echo json_encode(uploadprogress_get_info($_REQUEST['id']));
            exit();
        }
    
        if (@$_POST['UPLOAD_IDENTIFIER'])
            exit();
    ?>

    …where “id” is the uuid value of the UPLOAD_IDENTIFIER key.

    To be continued…

  • #15 / Oct 23, 2009 6:29pm

    rmedek

    131 posts

    Next I edited the uploadprogress.js script to work with PHP’s uploadprogress (the original script was linked to an apache module). The relevant part of that code:

    jQuery.uploadProgress = function(e, options) {
        jQuery.ajax({
            type: "GET",
            url: options.progressUrl + "?id=" + options.uuid,
            dataType: options.dataType,
            success: function(upload) {
    
                if (upload == null) {
                    window.clearTimeout(options.timer);
                    options.complete(upload);
                } else {
                    upload.percents = Math.floor(100 * parseInt(upload.bytes_uploaded) / parseInt(upload.bytes_total));
    
                    var bar = $.browser.safari ? $(options.progressBar, parent.document) : $(options.progressBar);
                    bar.css({width: upload.percents+'%'});
                    options.uploading(upload);
                
                }
            }
        });
    };</code></pre>
    
    …and finally edited ngen_file_field.js to run the progress code:
    
    <pre><code>// upload progress HTML
    $('form#entryform input[type=submit]').after('<div id="uploading">Uploading files…<span></span><div id="progress" class="bar"><div id="progressbar"> </div></div></div>');
    $('#uploading').hide();
    
    
    // add identifier
    var uuid = jQuery.uuid();
    $('form#entryform').prepend('<input name="UPLOAD_IDENTIFIER" type="hidden" value="' + uuid + '" />');    
    
    
    // fire script
    $('form#entryform').uploadProgress({
        jqueryPath: 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js',
        uploadProgressPath: '/system/extensions/fieldtypes/ngen_file_field/scripts/jquery.uploadProgress.js',
        start:function(){
            $('#uploading').animate({height: 'show', opacity: 'show'}, 500);
            $('input[type=submit]').attr('disabled',true);
        },
        uploading: function(upload) {$('#percents').html(upload.percents+'%');},
        interval: 2000,
        uuid: uuid,
    });

    I also edited the styles/ngen_file_field.css file and added some background images to get the progress bar looking good.

    I would just upload the whole shebang up here but I don’t want to break any licenses. But once you get a handle of what’s happening it’s easy enough to follow along:

      1. nGen_file_field gets loaded, dynamically inserts a progressbar and hides it immediately
      2. on form submit, the progress bar is shown, an iframe is created, and a PHP script is called dynamically from that iframe
      3. the PHP script grabs the upload information and reports back with an array of the data fields
      4. the javascript grabs that data, if it’s good it updates the progress bar on the parent page
      5. once the upload data is null (finished uploading, therefore no more info), the script fires an end function
      6. the whole shebang returns, and the form finishes the submission

    It’s also worth mentioning that I initially had a lot of sporadic issues until I removed TinyMCE from one of the custom fields on the page.

    That’s pretty much it.

    PHEW

    So…sorry for the stupid-long post and the crappy code, but hopefully this helps out some people.

    R

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases