Zobrazení průběhu uploadu prakticky
Školení, která pořádám
Možnosti pro zobrazení indikátoru, který by uživateli zobrazoval průběh odesílání formulářových dat (a především souborů v nich), jsem již rozebíral, nyní bych se rád zaměřil na praktickou ukázku v PHP 5.2.0 a novějším spolu s rozšířením APC. Ještě než se podíváme na ukázku kódu, musím si postesknout nad tím, že informaci o průběhu odesílání dat nezobrazuje přímo prohlížeč. Na rozdíl od situace při stahování dat má přesnou informaci o tom, kolik dat celkem je a jak je s jejich posíláním daleko.
Pokud je zapnuta konfigurační direktiva apc.rfc1867 a formulář obsahuje pole APC_UPLOAD_PROGRESS
, tak bude APC při přenášení všech následujících souborů ve formuláři aktualizovat sdílenou proměnnou upload_key
, kde key je hodnota zmíněného formulářového pole. K této proměnné můžeme následně přistoupit ze všech skriptů funkcí apc_fetch.
Pokud chceme průběh nahrávání souboru zobrazovat přímo ve stránce s formulářem, dá se to nejpohodlněji zařídit pomocí technologie AJAX. V pravidelných intervalech se budeme serveru dotazovat na stav přenosu a tuto informaci budeme zobrazovat na stránce.
<?php
$id = uniqid();
?>
<script type="text/javascript">
function progress_update(xmlhttp) {
if (xmlhttp.readyState == 4) {
document.getElementById('progress').innerHTML = xmlhttp.responseText;
window.setTimeout(progress_send, 1000);
}
}
function progress_send() {
send_xmlhttprequest(progress_update, 'GET', 'progress.php?id=<?php echo $id; ?>');
}
</script>
<form action="" method="post" enctype="multipart/form-data">
<input type="hidden" name="APC_UPLOAD_PROGRESS" value="<?php echo $id; ?>">
<input type="file" name="file">
<input type="submit" onclick="window.setTimeout(progress_send, 1000);">
<span id="progress"></span>
</form>
Viz send_xmlhttprequest
.
Pro identifikátor přenosu by se dalo použít např. session_id, nicméně pro případ, že by jeden uživatel odesílal více formulářů, je lepší použít nějaký zcela jednoznačný identifikátor.
Pravidelná aktualizace stavu přenosu svádí k použití funkce setInterval, u té bychom ale museli řešit případ, kdy se vyřízení dřívějšího požadavku chvíli pozdrží, takže jeho odpověď potom přepíše aktuálnější hodnotu. Proto budeme znovu čekat až poté, co se zobrazí předchozí stav.
Skript pro vracení dat už bude poměrně jednoduchý – z informací v poli upload_$_GET[id]
vypočteme procento přenesených dat a vypíšeme ho.
<?php
$progress = apc_fetch("upload_$_GET[id]");
echo ($progress ? number_format(100 * $progress["current"] / $progress["total"], 2) . "%" : "");
?>
Pokud bychom chtěli zobrazovat i další údaje, vrátili bychom XML soubor nebo JSON data se všemi informacemi – pole obsahuje kromě celkového objemu dat a už přenesené velikosti také položky pro přenosovou rychlost (rate
), název formulářového pole (name
), dočasnou cestu (temp_filename
) a původní jméno právě přenášeného souboru (filename
) a také informace o zrušeném přenosu (cancel_upload
) a dokončení (done
).
Při pokusech s odesíláním velkých souborů nezapomeňte správně nastavit maximální velikost nahrávaných souborů.
Diskuse
> musím si postesknout nad tím, že informaci o průběhu odesílání dat nezobrazuje přímo prohlížeč
A já se musím pochlubit, že můj prohlížeč to zobrazuje. Opera, když si nastavím Zobrazit -> Lišty -> Přizpůsobit -> Průběh načítání: Pod načítanou stránkou.
Matěj:
Dobrý den, když si stáhnu soubory APC-3.1.4 jak to mam nainstalovat, nebo prostě rozchodit? Není k tomu někde nějakej návod jak to apc nainstalovat a používat?
Děkuji
Tomáš Müller:
Neni v tom druhem snippetu chybicka?
$progress = apc_fetch("upload_$_GET[id]");
->
$progress = apc_fetch("upload_{$_GET[id]}");
?
Tomáš Müller:
To jsem se asi trochu unahlil, PHP to zkousne, ale ja bych to preci jen napsal takhle:
$progress = apc_fetch("upload_{$_GET['id']}");
Jakub Vrána :
Chybný by byl naopak způsob "upload_{$_GET[id]}", protože by se v něm id bralo jako konstanta. Když už, tak "upload_{$_GET["id"]}" nebo spíš rovnou "upload_" . $_GET["id"], ale je to samoúčelné, "upload_$_GET[id]" je zcela v pořádku.
Tomáš Müller:
Ano, PHP by vyhodilo notice, mel jsem za to, ze ho hodi i pri tom vasem zpusobu zapisu, ale neni tomu tak.
Kazdopadne diky za zajimavy clanek, rozhodne si to vyzkousim.
Tomáš Müller:
Takze jsem zpet, nyni ale doufam, ze muj komentar bude skutecne k veci a prinosny :)
Pokud instalujete APC jenom pro tuhle featuru, doporucuji upravit konfiguraci. Zejmena apc.shm_size - ta urcuje, jakou velikost ma jeden segment shared memory pouzivane pro cache. Defaultni hodnota je 30 a je to v megabajtech :) apc.shm_segments je pocet alokovanych segmentu, default je jeden.
tygr:
Muzete mi prosim poradit, kde najdu konfiguracni direktivu apc.rfc1867, kde ma byt umisten skript pro vraceni dat a zda na zprovozneni podpory APC v PHP staci v php.ini pridat extension=php_apc.dll?
Filip Krejčí:
Problem je ale v tom ze apc.rfc1867 neni thread safe, a posledni upload rusi stavy vsech predchozich. Tudiz je to cele o nicem.
Vlastovka:
Dobrý den,
Rád bych věděl, zda se nějak může uploadovat více souborů v 1 formuláři (resp. jak predat id vice souboru v 1 formulari - zde je jen 1 pole s nazvem APC_UPLOAD_PROGRESS)
díky
Andy:
Ovsem ze jde, staci formular upravit napriklad takto <input type="hidden" name="APC_UPLOAD_PROGRESS" value="nejaky id" />
<input type="file" name="file[]" />
<input type="file" name="file[]" />
apc_fetch() pak bude zobrazovat celkovy progress upload a prave uploadovany soubor napriklad
array(6) {
["total"]=>
int(627270)
["current"]=>
int(41326)
["filename"]=>
string(12) "PUTTYGEN.EXE"
["name"]=>
string(6) "file[]"
["done"]=>
int(0)
["start_time"]=>
float(1240498405.4505)
}
jak zjistit prubeh uploadu aktualniho souboru sem zatim nezjistoval, pripadne pro upload vice souboru lze udelat vice formularu a pomoci javascriptu je odesilat postupne :-)
tomasr:
Je nejake omezeni pro to APC na strane serveru? Kdyz sem to zkousel, tak behem uploadu se nedelo nic, az nakonci skocilo 100%, zadnej progress neni videt:(.
Andy:
Mám stejný problém, funkce apc_fetch() po celou dobu uploadu nic nevrací až po dokončení uploadu vrátí výsledek.
Andy:
Uz vim cim to je, je treba uvest
<input type="hidden" name="APC_UPLOAD_PROGRESS" value="id" />
PRED POLEM
<input type="file" name="file" />
protoze prohlizec posila jednotliva pole za sebou stejne jak jsou uvedena na strance, to znamena, pokud uvedete APC_UPLOAD_PROGRESS az za file, prohlizec posle id az po uploadu souboru
Diskuse je zrušena z důvodu spamu.