Pagina 1 di 5 1 2 3 ... ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 44

Discussione: [PILLOLA] Upload con progress bar per APC + jQuery

  1. #1

    [PILLOLA] Upload con progress bar per APC + jQuery

    Premessa
    Lo scopo della pillola è mostrare un modesto esempio su come sia possibile implementare una progress bar assieme ad altre informazioni tramite APC e l'utilizzo della libreria client jQuery.
    Tuttavia è possibile implementare quanto descritto anche tramite JavaScript "nudo e crudo" o qualunque altra libreria più o meno nota.
    Questa pillola non tratterà alcuna problematica diversa da quella specificata nel topic per cui se non conoscete affatto JavaScript, jQuery o PHP5 consiglio di approfondire ogni argomento in questo stesso sito (pillole/articoli/guide) prima di proseguire.

    ---FILMATO DEMO----------------------------------------
    http://www.youtube.com/watch?v=aXZ3WYdB5sQ
    --------------------------------------------------------------

    APC - Alternative PHP Cache
    Questa estensione, in particolare la direttiva rfc1867, è sfruttabile a partire da PHP 5.2 e superiore.
    Il vero scopo di tale libreria è ben diverso da quello proposto in questa pillola ma allo stesso tempo la direttiva in esame, la rfc1867, è presente solo in APC.
    Per installare APC potete seguire i suggerimenti presenti nel sito php.net sotto la voce installazione librerie PECL.
    Per gli utenti PAMPA o per i più esperti con l'ambiente Windows (Apache e PHP installati manualmente) è sufficiente aggiungere almeno queste due linee all'interno del file php.ini
    codice:
    extension=php_apc.dll
    apc.rfc1867 = On
    sotto la voce Dynamic Extensions.
    La direttiva rfc1867 è infatti disabilitata di default poichè il tracking di un upload non è una procedura threadsafe, pertanto consiglio di essere documentati a sufficienza a riguardo prima di scegliere di utilizzare questa procedura in produzione.


    jQuery
    Una delle tante librerie client disponibili, una delle più riuscite, se non altro per il successo dimostrato dall'utilizzo da parte di numerosi sviluppatori più o meno esperti.
    Sebbene l'idea iniziale era quella di fare un plugin per jQuery ho preferito creare un file più semplice da anlizzare, eliminando problematiche di scope, riferimenti this ed altro ancora.
    Il codice client proposto è comunque facilmente implementabile in un eventuale plugin nonchè totalmente compatibile con altre librerie, qualunque esse siano, purchè non "annientino" la variabile globale jQuery.


    Upload e problematiche annesse
    L'aggiunta di files sul server è una problematica comune affrontabile in tanti modi.
    Uno dei più usabili ed accattivanti è sicuramente quello di poter mostrare al cliente/utente lo stato di upload del file.
    Così facendo si ovvia al problema dello "stress da attesa", impegnando occhi e mente a seguire quanto ancora manchi assicurandolo virtualmente che qualcosa stia accadendo.
    Il pensiero "ma quanto ci mette / a che punto è ?" viene soppiantato dall'eppur si muove e l'invidia suscitata da almeno un paio d'anni da parte del mondo ActionScript ha "causato" lo sviluppo di alternative differenti, basate sullo stesso ActionScript oppure su librerie server dedicate.


    Upload, quale futuro ?
    Sebbene io stesso stia dedicando in questo istante del tempo per aggiungere ad un normale form di invio file caratteristiche impensabili fino a pochi anni fa, l'unico modo realmente portabile ed affidabile per risolvere il problema è affidarsi al client.
    Per creare una progress bar come quella che sto per mostrare è infatti necessario stressare più del necessario il server, richiamandolo molteplici volte e costringendolo a monitorare "variabili" che avrebbe volentieri ignorato prima dell'avvento Ajax.
    L'unica tecnologia attualmente riconosciuta come molto valida, affidabile nonchè ampiamente compatibile e capace di spostare la problematica sul client piuttosto che sul protocollo HTTP e l'interazione col server, è il player di Adobe, tramite il quale si sono creati moduli portabili e di semplice implementazione come SWFUpload.
    Ciò nonostante le prossime release di JavaScript dovrebbero permettere di utilizzare metodologie analoghe a quelle ActionScript ... per cui se avete pazienza aspettate ancora un pò prima di proseguire e scegliere la strada del polling client / server ...


    La form per l'upload
    Se state ancora leggendo siete dei testardi ... e siete quindi, in questo settore, i benvenuti.
    La pagina per gestire l'upload è molto semplice:
    codice:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
    	<head>
    		<title>PHP Upload with APC and jQuery</title>
    		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
    		<script type="text/javascript" src="jquery-1.2.1.js"></script>
    		<script type="text/javascript" src="apcquery.js"></script>
    		<link rel="stylesheet" type="text/css" href="apcquery.css" />
    		<style type="text/css">
    		body {
    			font-family: Verdana, Helvetica, sans-serif;
    			font-size: 1em;
    		}
    		fieldset {
    			border: 0;
    		}
    		fieldset legend {
    			display: block;
    			font-weight: bold;
    			padding: 4px;
    		}
    		label {
    			display: none;
    		}
    		input {
    			border: 1px solid #DDD;
    			background-color: #EEE;
    			font-size: .8em;
    		}
    		div.apcquery {
    			visibility: hidden;
    		}
    		</style>
    	</head>
    	<body>
    		<div>
    			<form enctype="multipart/form-data" method="post" action="APCQuery.class.php?redirect=index.html">
    				<fieldset>
    					<legend>Please choose a file</legend>
    					<label for="user-file">your file</label>
    					<input type="file" id="user-file" name="user-file" tabindex="1" />
    					<input type="submit" value="Upload"  tabindex="2" />
    					<div class="apcquery">
    						<span class="info">Total</span><span class="total"></span>
    						<span class="info">Sent</span><span class="loaded"></span>
    						<span class="info">Rate</span><span class="rate"></span>
    						<span class="percent"></span>
    					</div>
    				</fieldset>
    			</form>
    		</div>
    	</body>
    </html>
    I files necessari sono la stessa libreria jQuery, in questo esempio la versione 1.2.1, il mio file JavaScript ed in fine il file CSS dedicato al mio file JavaScript.
    Gli stili in linea con la pagina sono solo un esempio e possono essere modificati a piacere ma se volete far apparire il "contenitore di informazioni" vi consiglio di non cambiare l'ultima parte
    codice:
    div.apcquery {
    	visibility: hidden;
    }
    Questo XHTML spero sia di facile comprensione, l'unico appunto da fare credo sia per l'action della form.
    APCQuery.class.php è la classe PHP5 che si occuperà della gestione delle informazioni (mostrata poi assieme al resto) mentre la variabile $_GET di nome redirect serve, sempre alla classe APCQuery, a permettere che la form sia utilizzabile con o senza JavaScript.



    La classe server
    codice:
    <?php
    // (C) Andrea Giammarchi - 24/10/2007
    class APCQuery{
    
    	// proprietà privata, assegnata nel costruttore
    	private	$output = '';
    	
    	// metodo pubblico statico, forza il browser ad ignorare eventuali versioni in cache della stessa pagina
    	public static final function noCache(){
    		header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    		header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
    		header('Cache-Control: no-store, no-cache, must-revalidate');
    		header('Cache-Control: post-check=0, pre-check=0', false);
    		header('Pragma: no-cache');
    	}
    	
    	// costruttore, richiede un parametro stringa con un file, in questo caso
    	// quello che dovrà gestire l'upload e/o controlli e/o altro eventuale
    	public final function __construct($requireFile){
    	
    		// se la richiesta è tramite Ajax ed esiste
    		if(isset($_GET['APC_PK']))
    			// si crea solo un output di tipo JSON
    			$this->output = $this->createJSON();
    		// se invece la richiesta è di tipo post, l'upload è appena terminato
    		// si crea un output JavaScript al fine di semplificare le operazioni client
    		elseif(isset($_POST['APC_UPLOAD_PROGRESS'])){
    			// ma se il file per gestire l'upload chiude il programma
    			// o fa altro è possibile cambiare il comportamento
    			require $requireFile;
    			// alrtrimenti si prosegue creando l'output JavaScript
    			$this->output = $this->createScript();
    		}
    		// se non è stato richiesto niente ne in get ne in post, o meglio
    		// non è presente il campo APC_UPLOAD_PROGRESS
    		// ed è presente la variabile redirect, il client
    		// non aveva JavaScript abilitato ...
    		elseif(isset($_GET['redirect'])){
    			// si fanno le operazioni di upload
    			require $requireFile;
    			// e si reindirizza il client alla pagina specificata
    			header('Location: '.$_GET['redirect']);
    		}
    	}
    	
    	// restituisce il contenuto della variabile output
    	// e non la variabile privata stessa
    	// qualora si tenti di stamparare o convertire a stringa
    	// un'istanza di questa classe
    	public final function __toString(){
    		return	$this->output;
    	}
    	
    	// verifica tutte le voci APC_PK (progress_key) e per ognuna di queste crea l'informazione
    	// per poi restituirla come stringa JSON
    	protected final function createJSON(){
    		$APC_UPLOAD_PROGRESS = is_array($_GET['APC_PK']) ? $_GET['APC_PK'] : array($_GET['APC_PK']);
    		for($i = 0, $j = count($APC_UPLOAD_PROGRESS); $i < $j; $i++)
    			$APC_UPLOAD_PROGRESS[$i] = apc_fetch('upload_'.$APC_UPLOAD_PROGRESS[$i]);
    		return	json_encode($APC_UPLOAD_PROGRESS);
    	}
    	
    	// assegna la variabile o l'array di variabli APC_UPLOAD_PROGRESS alla $_GET['APC_PK']
    	// per poi restituire un tag capace di memorizzare una variabile facilmente raggiungibile dal client
    	protected final function createScript(){
    		$_GET['APC_PK'] = $_POST['APC_UPLOAD_PROGRESS'];
    		return	'<script type="text/javascript">response='.$this->createJSON().';</script>';
    	}
    }
    
    // un fake main per permettere a questo file di essere incluso altrove al fine di poter riutilizzare la classe
    // APCQuery anche da altri programmi ... in poche parole un'emulazione in stile Python
    if($_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF'] === str_replace('\\', '/', __FILE__)){
    	// headers per evitare il caching dei dati
    	APCQuery::noCache();
    	
    	// uscita dal programma, exit stampa informazioni sotto forma di stringa
    	// se viene specificato un parametro ... ergo in questo caso richiama 
    	// in automatico il metodo toString dell'istanza
    	exit(new APCQuery('upload.php'));
    }
    ?>
    La $_GET['APC_PK'], come la $_POST['APC_UPLOAD_PROGRESS'], è gestita dal client ... che verrà mostrato a breve


    La pagina di upload
    Questa pagina ha il compito di gestire le informazioni (files) che si vorrebbero upoadare.
    Al suo interno è possibile verificare dimensione file ed altro ancora per far fallire o completare l'upload.
    codice:
    <?php
    if(isset($_FILES['user-file']))
    	@move_uploaded_file($_FILES['user-file']['tmp_name'], 'files/'.$_FILES['user-file']['name']);
    ?>

    Il CSS client
    Questo CSS è dedicato ai vari div con classe apcquery, dando per scontato che la loro struttura sia identica a quella mostrata nel file XHTML.
    L'appunto degnodi nota è che a prescindere da colori, dimensioni, testo e tutto il resto, l'iframe con classe apcquery dovrebbe essere lasciato come è.
    Il motivo è semplice, se si maschera l'iframe mettendolo in display: none oppure visibility: hidden, alcuni browsers (per lo più il solito Explorer) non lo accetteranno come target valido per una form.
    In soldoni se si tenta di nascondere l'iframe il tutto potrebbe non funzionare.
    Siccome in questo caso l'iframe serve solo come "canestro per buttare i files" (perdonate il pessimo paragone), tanto vale evitare di fargli cambiare il layout (position: absolute) e posizionarlo dove nessuno potrà mai vederlo (top e left negativi ... a meno 10000px).
    codice:
    div.apcquery {
    	width: 280px;
    	padding: 2px;
    	margin-top: 8px;
    	border: 4px solid #AAA;
    	background-color: #FFF;
    	color: #444;
    	text-align: left;
    	font-size: .8em;
    }
    div.apcquery .info,
    div.apcquery .total,
    div.apcquery .loaded,
    div.apcquery .rate {
    	display: block;
    	float: left;
    	overflow: hidden;
    	margin-bottom: 2px;
    }
    div.apcquery .info {
    	width: 60px;
    }
    div.apcquery .total,
    div.apcquery .loaded,
    div.apcquery .rate {
    	text-align: right;
    	width: 216px;
    }
    div.apcquery .percent {
    	clear: left;
    	display: block;
    	background-color: #CCC;
    	width: 100%;
    	height: 16px;
    }
    iframe.apcquery {
    	position: absolute;
    	top: -10000px;
    	left: -10000px;
    }
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  2. #2
    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.
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  3. #3
    Stavo rimuginando sulla strana scritta APC
    e upload apparsa su un altro thread ed ecco ......



    che dire grazie di esistere



    Mo me la leggo con calma.


    Without faith, nothing is possible. With it, nothing is impossible
    http://ilwebdifabio.it

  4. #4
    Utente di HTML.it L'avatar di gianiaz
    Registrato dal
    May 2001
    Messaggi
    8,050
    grandissimo andr3a, complimenti davvero!

  5. #5

    Screen Cast - Demo APCQuery

    Ho appena uploadato su YouTube una dimostrazione pratica del risultato finale:
    http://www.youtube.com/watch?v=aXZ3WYdB5sQ

    Sarebbe stato bello poterlo mettere come object a inizio pillola ma mi sa che il forum non lo permette.




    che dire grazie di esistere
    ...
    grandissimo andr3a, complimenti davvero!
    una passeggiata :sborò:
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  6. #6
    100 lettori e nessun commento ... non che mi aspettassi una medaglia ( :muttley: ) ma nemmeno un quinta pagina senza link nel topic in rilievo ...


    mods ... ci siete? (auguri bubu!)

    mi piacerebbe spostare il link al video YouTube all'inizio del primo post ... se possibile, e avere un posticino-ino-ino ( :flanders: ) nel 3D in rilievo, chiedo troppo? :master:
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  7. #7
    Utente di HTML.it L'avatar di gianiaz
    Registrato dal
    May 2001
    Messaggi
    8,050
    Originariamente inviato da andr3a
    100 lettori e nessun commento ... non che mi aspettassi una medaglia ( :makley: ) ma nemmeno un quinta pagina senza link nel topic in rilievo ...


    mods ... ci siete? (auguri bubu!)

    mi piacerebbe spostare il link al video YouTube all'inizio del primo post ... se possibile, e avere un posticino-ino-ino ( :flanders: ) nel 3D in rilievo, chiedo troppo? :master:
    Bhe calcola che trovare php 5.2 in produzione non è proprio una cosa da tutti...

    Comunque eccoti servito






  8. #8
    Originariamente inviato da gianiaz
    Bhe calcola che trovare php 5.2 in produzione non è proprio una cosa da tutti...
    in Quake 3 al tempo delle prime connessioni 56Kb (lag) si diceva che un giocatore schivava dal futuro e sparava nel passato, ciò nonostante erano in tanti a giocare


    Grazie per la medaglia
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  9. #9
    io proporrei un articolino ad andrea marzilli
    w la topa

  10. #10
    Anche io credo che potrebbe essere un'articolo interessante... Che ne dici Andrea?
    _____________________________________
    Fatti non foste a viver come bruti...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2017 vBulletin Solutions, Inc. All rights reserved.