• Resolved Chris Huff

    (@brochris)


    I’m so very close to being able to release a free plugin.

    Upon uploading media, my plugin automatically transfers audio and video files to an external server (Archive.org). The part that I’m hung up on is the progress bar, showing the progress of transferring the file to Archive.org. But instead of a smoothly growing progress bar, it stays at 0% and then jumps to 100% once it’s done.

    Relevant code from the plugin:

    // Set all the options if they don't exist yet
    add_option('aou_accesskey',"");
    add_option('aou_secretkey',"");
    add_option('aou_progress',"");
    update_option('aou_progress','0');
    
    function progressCallback( $download_size, $downloaded_size, $upload_size, $uploaded_size ){
        static $previousProgress = 0;
    
        if ( $upload_size == 0 )
            $progress = 0;
        else
            $progress = round( $uploaded_size * 100 / $upload_size );
    
        if ( $progress > $previousProgress){
            $previousProgress = $progress;
            update_option('aou_progress',$progress);
    	    }
    	}
    
    function aou_upload_file($file) {
    	$ias3accesskey = get_option('aou_accesskey',"");
    	$ias3secretkey = get_option('aou_secretkey',"");
    
    	$filename = str_replace(' ', '-', $file['name']);
    	$file_no_ext = preg_replace('/\\.[^.\\s]{3,4}$/', '', $filename);
    
    	$file_read = fopen($file['tmp_name'], 'r');
    	$upload_file_url = 'https://archive.org/download/' . $filename . '/' . $filename;
    
    	$headers = array(
    'Authorization: LOW ' . $ias3accesskey . ':' . $ias3secretkey,
    'x-amz-auto-make-bucket:1',
    'x-archive-meta01-collection:opensource_' . $mediatype,
    'x-archive-meta-title:' . $file['name']
    );
    
    	$ch = curl_init();
    	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    	curl_setopt($ch, CURLOPT_HEADER, true);
    	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    	curl_setopt($ch, CURLOPT_URL, 'https://s3.us.archive.org/' . $filename . '/' . $filename);
    	curl_setopt($ch, CURLOPT_PUT, true);
    	curl_setopt($ch, CURLOPT_INFILE, $file_read);
    	curl_setopt($ch, CURLOPT_INFILESIZE, filesize($file['tmp_name']));
    	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    	curl_setopt($ch, CURLOPT_VERBOSE, false);
    	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    	curl_setopt($ch, CURLOPT_NOPROGRESS, false );
    	curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progressCallback');
    	curl_setopt($ch, CURLOPT_BUFFERSIZE, 25);
    	curl_exec($ch);
    	curl_close($ch);
    	fclose($file_read);  
    
        return $file;
        }
    
    add_filter('wp_handle_upload_prefilter','aou_upload_file');
    
    function aou_css_head() {
    	global $pagenow;
    
    	if ($pagenow == 'media-new.php'){ ?>
    		<style type="text/css">
    		#aou_progress {
    		  display:block;
    		  height:15px;
    		  background-color:#ddd;
    		  text-align:right;
    		  overflow:hidden;
    		  font-size:10px;
    		  color:#aaa;
    		  position:relative;
    		  padding-right:3px;
    		}
    		#aou_progress_bar {
    		  position:absolute;
    		  top:0;
    		  left:0;
    		  width:0%;
    		  height:15px;
    		  background-color:#cdf;
    		  padding-right:3px;
    	      overflow:hidden;
    	    }
    	    </style>
    
    	    <script>
    
    		window.setInterval(function(){
    			var xhttp = new XMLHttpRequest();
    			xhttp.onreadystatechange = function() {
    				var progressElement = document.getElementById('aou_progress_bar');
    				if (xhttp.readyState == 4 && xhttp.status == 200 && progressElement.innerHTML != '100%') {
    					progressElement.style.width = xhttp.responseText + '%';
    					progressElement.innerHTML = xhttp.responseText + '%';
    					}
    				};
    			xhttp.open("GET", "https://<?php echo $_SERVER['SERVER_NAME']; ?>/wp-content/plugins/archiveorg-uploads/progress.php", true);
    			xhttp.send();
    			}, 125);
    
    		</script>
    <?php
        	}
        }
    
    add_action('admin_head', 'aou_css_head');
    
    function aou_progress_bar() {
        global $pagenow;
        if ($pagenow == 'media-new.php'){
    	    echo '<div id="aou_progress">Archive.org Uploads Progress<div id="aou_progress_bar">0%</div></div>';
    		}
    	}

    add_action(‘all_admin_notices’,’aou_progress_bar’);`

    <strong>progress.php</strong>

    <?php
    require_once('../../../wp-load.php');
    global $wpdb;
    echo $wpdb->get_var( "SELECT option_value FROM wp_options WHERE option_name='aou_progress'" );
    ?>

    So, so basically, the callback of the upload updates the aou_progress option in the database, and this option is written via progress.php, which should be checked for changes every 1/8 second, and the progress bar should grow.

    But obviously I did something wrong here. I’m wondering if it can’t check progress.php for a change while it’s transferring the file via curl? If that’s true, is there a way to get around it?

Viewing 2 replies - 1 through 2 (of 2 total)
  • if update_option('aou_progress','0'); is located in your main plugin file then it gonna be a problem
    because any request to your server (refreshing page, ajax call, etc) will trigger that method call
    which means it will always reset aou_progess value into 0
    you might need to put additional logic for that

    another thing to be noted is: CURLOPT_PROGRESSFUNCTION
    check this out: https://php.net/manual/en/function.curl-setopt.php#116866

    for PHP version < 5.5.0, CURLOPT_PROGRESSFUNCTION pass 4 arguments
    and for PHP version >= 5.5.0, CURLOPT_PROGRESSFUNCTION pass 5 arguments
    which means it may break without version checking

    you also need to be careful with CURLOPT_PROGRESSFUNCTION
    because it is a callback function which run separately and standalone
    which means a second call to progressCallback can not recognize previous state from progressCallback at the first time
    so you just need to be aware of $upload_size and $uploaded_size ($previousProgress is unused)

    then the last thing is, it may not 100% reflect your current progress because it is a race between:
    – callback from CURLOPT_PROGRESSFUNCTION
    – and your AJAX under window.setInterval

    the progress bar might work for a large file size upload but it may “not work” for a small file size upload
    “not work” -> because CURLOPT_PROGRESSFUNCTION might already reach 100% before your AJAX call had a chance to update the progress bar gradually

    Thread Starter Chris Huff

    (@brochris)

    Thanks for helping me out! Your last tip especially helped me the most. Since it was, essentially, a race between the file progress being updated and the actual progress bar being updated, I found a good balance between the two. Also, and this was probably the biggest thing, the progress.php file was loading all of WordPress a second time (require_once(‘../../../wp-load.php’);) just to get one option from the database. So I converted progress.php to use a flat file written and read with javascript, which speeds up the whole process a ton.

    Again, thanks for your insight!

Viewing 2 replies - 1 through 2 (of 2 total)
  • The topic ‘Update progress bar from database’ is closed to new replies.