Il codice client
Siamo arrivati quasi alla fine ma non per questo alla parte meno importante ... il codice JavaScript.
codice:
// (C) Andrea Giammarchi

// closure per non avere problemi di ambiguità con la funzione dollaro
// inviata come variabile globale jQuery
(function($){$(function(){

	// funzione fulcro della gestione upload
	// il this è riferito alla form del caso
	function APCQuery(){
		var	i = 0,		// indice
			ids = [];	// lista di id univoci creati per inviare al server
					// dei valori "affidabili"
		// per ogni input di tipo file ...
		$(this).find("input").filter("[type=file]").each(function(){
			// si aggiunge un campo hidden immediatamente prima
			// utilizzando il nome APC_UPLOAD_PROGRESS ed un valore presumibilmente e preferibilmente univoco
			$(this).before(
				'<input type="hidden" name="APC_UPLOAD_PROGRESS[]" value="' +
					// valore salvato nella lista di id
					(ids[i++] = i + Math.random()) +
				'" />'
			);
		});
		
		// l'iframe utilizzato come target non è ancora presente
		// è fondamentale inserirlo in un nodo DOM esterno al form
		// altrimenti non verrebbe accettato come target
		$(this.parentNode).append(
			'<iframe class="apcquery" name="' +
				// il nome dell'iframe deve essere univoco e per far si che questo avvenga
				// lo si assegna sfruttando un prefisso fittizio "apcqueryiframe"
				// più l'insieme degli id univoci concatenati tramite un carattere qualunque,
				// possibilmente ASCII standard, in questo caso il carattere "-"
				(this.target = "apcqueryiframe" + ids.join("-")) +
			'" id="'
				// per compatibilità si assegna anche l'id utilizzando
				// lo stesso nome univoco scelto per il name
				+ this.target +
			'" src="' +
				// per evitare problemi (avvisi) in ambiente sicuro (SSL)
				// è sempre meglio mettere un source all'iframe
				// (Internet Explorer chiederebbe una conferma codice insicuro se omesso)
				(this.action = this.action.split("?")[0]) +
			'"></iframe>'
		);
		// da notare che durante la creazione dell'iframe sono stati riassegnati
		// sia il target che l'action della form.
		// Nel primo caso, il target, si aggiunge l'iframe per evitare che il submit
		// della form vada all'altra pagina mentre nel secondo, l'action,
		// si elimina la querystring dedicata al redirect e quindi 
		// agli utenti che non hanno JavaScript abilitato o che non sono
		// compatibili con questo codice
		
		// non resta che assegnare l'evento "onsubmit" della form ...
		$(this).submit(function(){
		
			// per prima cosa l'evento deve capire se effettivamente c'è qualcosa da fare ... 
			// dato che si sfrutta il client per l'upload, tanto vale sfruttarlo anche per diminuire le chiamate al server
			var	result = !!$(this).find("input").filter("[type=file]").filter(function(){return !!this.value}).length;
			
			// se tra i vari input di tipo file almeno uno è stato specificato ed ha quindi un valore
			// si procede con il submit
			if(result){
				var	delay = 500,		// tempo, in millisecondi, ogni quanto il client chiede informazioni al server
					timeout = 0,		// intervallo assegnato dalla funzione setTimeout
					apcquery = $(this).find("div.apcquery"),	// contenitore informazioni all'interno della form
					iframe = $(this.parentNode).find("iframe[name=" + this.target + "]").get(0),	// l'iframe utilizzato come target del form
					self = this,		// riferimento alla form stessa, utile per le funzioni innestate in intervalli e/o altro
					onload = function(){	// callback richiamata ad iframe caricato
						// si annullano gli eventi precedentemente assegnati all'iframe
						iframe.onload = iframe.onreadystatechange = function(){};
						
						// si annulla il timeout precedentemente assegnato
						clearTimeout(timeout);
						
						// si elabora il risultato presente, grazie alla classe PHP5, nella window dell'iframe e non nel documento
						// (più compatibilità per meno operazioni)
						APCResult(apcquery, iframe.contentWindow.response, function(){
							// si mostra per il tempo scelto le informazioni complete ...
							setTimeout(function(){
								// si riabilita il bottone submit
								$(self).find("input[type=submit]").each(function(){
									this.disabled = false;
								});
								// e si rinascondono le informazioni
								apcquery.css("visibility", "hidden");
							}, delay);
						});
					};
				
				// proprietà utilizzata esclusivamente da Explorer ma se presente, anche da Opera
				iframe.onreadystatechange = function(){
					// se lo stato dell'iframe è caricato o completo
					if(/loaded|complete/i.test(iframe.readyState))
						// si richiama la callback onload
						onload();
				};
				
				// evento utilizzato da tutti i browsers tranne che da Explorer (al solito insomma)
				iframe.onload = onload;
				
				// da notare che non è possibile assegnare la callback onload direttamente ad iframe.onload
				// per poi richiamarla all'onreadystatechange per il semplice motivo che Explorer non darà
				// errore ... ma non effettuerà nemmeno la chiamata (al solito insomma ...)
				
				// tentativo di evitare doppio upload, stress inutile per il server
				$(this).find("input[type=submit]").each(function(){
					// si disabilita il submit della form (uno o più di uno se presenti)
					this.disabled = true;
				});
				
				// si assegna il valore in percentuale allo span dedicto a mostrare lo stato sotto forma di barra (zero inizialmente)
				apcquery.find(".percent").css("width", "0%");
				
				// si mostra il contenitore di informazioni e si assegna il valore zero a tutti i campi
				apcquery.css("visibility", "visible").find(".total,.loaded,.rate").text(APCSize(0));
				
				// si assegna un timeout per cominciare a richiedere informazioni al server
				// ... è totalmente inutile farlo immediatamente, l'upload deve ancora cominciare ...
				timeout = setTimeout(function(){
					var	i = 0,				// indice array
						result = [],			// array risultati
						callee = arguments.callee;	// questa stesa funzione
					
					// per ogni input che invia l'informazione APC_UPLOAD_PROGRESS ...
					$(self).find("input")
					.filter(function(){
						return	this.name === "APC_UPLOAD_PROGRESS[]"
					})
					// si assegna ala lista risultati la chiave APC_PK contenente il valore dell'input
					// gestiti entrambi dalla classe PHP5
					.each(function(){
						result[i++] = 'APC_PK[]=' + this.value;
					});
					
					// si richiama la pagina server, in questo caso la classe PHP5, concatenando
					// le chiavi ed i rispettivi valori
					$.getJSON(self.action + "?" + result.join("&"),
					// una volta ricevuto il risultato ...
					function(data){
						// lo si invia alla funzione dedicata al fine di mostrare quanto
						// ricevuto dal server
						APCResult(apcquery, data, function(){
							// questa callback serve per evitare di intasare il server di chiamate
							// Se si utilizza un intervallo infatti il client
							// continuerà impoerterrito a richiedere informazioni mentre
							// l'opzione più ovvia è attendere che almeno l'ultima richiesta
							// sia stata elaborata.
							// tutto questo è gestito nella funzione APCResult
							timeout = setTimeout(callee, delay);
						})
					});
				}, delay);
			};
			
			// si restituisce il risultato per attivare o disattivare il submit
			// (se non c0è alcun input di tipo file selezionato o con un valore restituisce false, non accade niente)
			return	result;
		});
	};
	
	// funzione di gestione risultati
	function APCResult(div, data, callback){
		var	loaded = 0,	// totale bytes inviati
			total = 0,	// totale bytes necessari per terminare l'upload
			i = 0;		// indice array (data)
		
		// è necessario avere un riferimento per gestire
		// il rate, in questa pillola presente fin da subito
		// e non solo ad upload terminato, come previsto da APC
		if(!div.__APCRate)
			div.__APCRate = {
				time:new Date,	// tempo richiesta
				value:0		// dati scaricati
			};
		while(i < data.length){
		
			// se data[i] non contiene il valore false,
			// default quando il server non sa cosa fare,
			// si assegnano tutti i caricati e tutti i totali
			if(data[i]){
				loaded += data[i].current;
				total += data[i].total;
			};
			++i;
		};
		
		// per avere un rate verosimile si sottrae il totale dati caricati
		// a quelli precedenti per poter gestire un rapporto upload / tempo trascorso
		div.__APCRate.value = loaded - div.__APCRate.value;
		
		// si scrive il totale tramite la funzione APCSize
		div.find(".total").text(APCSize(total));
		
		// si scrive il totale tramite la funzione APCSize
		div.find(".loaded").text(APCSize(loaded));
		
		// si scrive il rate eliminando la dicitura bytess (convertita in bps)
		div.find(".rate").text(APCSize(parseInt((div.__APCRate.value * 100) / (new Date - div.__APCRate.time)) || 0).replace(/bytes/, "b") + "ps");
		
		// si assegna la percentuale in base al rapporto bytes uploadati / totale bytes da uploadare
		div.find(".percent").css("width", (Math.round((loaded * 100) / total) || 0)+ "%");
		
		// si aggiorna il tempo per il rate successivo
		div.__APCRate.time = new Date;
		
		// se è stata specificata una callback la si richiama
		// ovvero si assegna il prossimo setTimeout per avere informazioni
		// o si esce dal "programma" - caso onload
		if(callback)
			callback();
	};
	
	// resittuisce un risultato compresinbile, da bytes a Kb, Mb o altro
	function APCSize(value){
		var	type = ["bytes", "Kb", "Mb", "Gb", "Tb", "Zb"],
			i = 0;
		while(value > 1024 && ++i)
			value /= 1024;
		return	(i ? value.toFixed(2) : Math.ceil(value)) + " " + type[i];
	};
	
	// si avvia il programma automatizzato scegliendo solo
	// le form della pagina che contengono un input di tipo file
	$("form").each(function(){
		if(0 < $(this).find("input").filter("[type=file]").length)
			APCQuery.call(this);
	});
	
	// normalizzazione numerica, funzione toFixed non presente in IE5.5 o inferiore
	if(!Number.prototype.toFixed)
		Number.prototype.toFixed = function(max){
			var	result = Math.pow(10, parseInt(max)), tmp;
			result = String(Math.round(this * result) / result);
			if(max > 0){
				tmp = result.split(".");
				tmp[1] = (tmp[1] || "") + new Array(++max - (tmp[1] ? tmp[1].length : 0)).join("0");
				result = tmp.join(".");
			};
			return	result;
		};
})})(jQuery);

Ultime informazioni
Per agevolare i vari copia e incolla ho creato un archivio contenente tutto il necessario per testare quanto proposto.
Ricordo che ovviamente se testate il tutto in locale e vedere dei risultati dovete aumentare le direttive di upload del php.ini (upload_max_filesize e post_max_size) e che con un portatile sicuramente poco performante ho osservato quanto previsto uploadando un file da 40 mega in su, su PC veloci provate con files di 80 mega ed oltre ma ricordate di settare le variabili per l'upload a 100M o più.
On-line invece vi basta avere PHP 5.2 o superiore, APC con la rfc abilitata e la libreria json, che salvo configurazioni per me incomprensibili, dovrebbe essere abilitata di default dalla versione 5.2 di PHP.
Per concludere con le informazioni, qualora qualcuno si sia accorto della notazione array utilizzata sia per la post, APC_UPLOAD_PROGRESS[], che per la get, APC_PK[], posso solo dire che sebbene questa pillola sia teoricamente compatibile con upload multipli, la libreria stessa è ancora in fase di sviluppo e non risulta tutt'ora compatibile con questa procedura.
La speranza è che nella prossima versione PECL si possano gestire più informazioni e che la pillola diventi automaticamente utile e compatibile anche con upload multipli implementati tramite XHTML o JavaScript che sia.


Con la speranza di aver scritto il tutto in modo comprensibile (perdonatemi eventuali errori ma mentre scrivevo guardavo Doctor House ) resto a disposizione per eventuali delucidazioni su parti poco chiare del codice utilizzato.