O PHP não possui nativamente nada que permita monitorar o upload de um arquivo. Hoje no mercado existem duas opções disponíveis para fazer isso:
Como meu servidor não me permite fazer o patch no PHP e eu particularmente acho muito chato ter que ficar aplicando patches no PHP toda vez que eu atualizo sua versão e etc… Aqui vai um rápido post explicando como instalar e usar a extensão PECL.
Para instalar é necessário executar o comando:
pecl install uploadprogressExemplos podem ser achados aqui:
Para os preguiçosos ou aqueles que precisem de uma ajudinha extra….
Aqui vai:
Presumo que se você chegou aqui, você ja deve ter instalado o componente no seu servidor e devidamente restartado o Apache (se você não fez isso ainda, então vai lá… eu espero aqui).
Vou usar as páginas acima por preguiça de escrever meu próprio código, mas eu vou explicar o que elas estão fazendo e porque.
Vamos à descrição das páginas:
index.php – é o form e onde tudo acontece. Aqui temos o Javascript de upload e o formulário.
info.php – é usado para buscar informações sobre o upload atual e retornar isso ao script
server.php – é o que efetivamente processa o upload. Ele é o que salva o arquivo e para o script de monitoramento.
Bom agora que sabemos o que cada um faz, vamos explicar em detalhes:
index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | <?php $id = md5(microtime() . rand()); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script> var UP = function() { /* private variables */ var ifr = null; var startTime = null; var infoUpdated = 0; var writeStatus = function(text,color) { var statDiv = document.getElementById("status"); if (color == 1 ) { statDiv.style.backgroundColor = "green"; } else if (color == 2 ) { statDiv.style.backgroundColor = "orange"; } else if (color == 3 ) { statDiv.style.backgroundColor = "red"; } else { statDiv.style.backgroundColor = "white"; } statDiv.innerHTML = text; }; return { start: function() { ifr = document.getElementById("ifr"); startTime = new Date(); infoUpdated = 0; this.requestInfo(); }, stop: function(files) { if (typeof files == 'undefined' || files) { var secs = (new Date() - startTime)/1000; var statusText = "Upload succeeded, it took " + secs + " seconds. <br/> "; if (infoUpdated > 0) { writeStatus(statusText + "You had " + infoUpdated + " updates from the progress meter, looks like it's working fine",1); } else { statusText += "BUT there were no progress meter updates<br/> "; if (secs < 5) { writeStatus(statusText + "Your upload was maybe too short, try with a bigger file or a slower connection",2); } else { writeStatus(statusText + "Your upload should have taken long enough to have an progress update. Maybe it really does not work...",3); } } } else { writeStatus('PHP did not report any uploaded file, maybe it was too large, try a smaller one (max. <?php echo ini_get('upload_max_filesize');?>)',3); } startTime = null; }, requestInfo: function() { ifr.src="info.php?ID=<?php echo $id;?>&"+new Date(); }, updateInfo: function(percent, estimatedSeconds) { if (startTime) { if (percent) { infoUpdated++; writeStatus("Download started since " + (new Date() - startTime)/1000 + " seconds. " + Math.floor(percent * 100) + "% done, " + estimatedSeconds + " seconds to go"); } else { writeStatus("Download started since " + (new Date() - startTime)/1000 + " seconds. No progress info yet"); } window.setTimeout("UP.requestInfo()",500); } } } }() </script> <title>php5.2 uploadprogress Meter - Simple Demo</title> </head> <body> <form target="ifr2" action="server.php" enctype="multipart/form-data" method="post"> <input value="<?php echo $id;?>" /> <label>Select File:</label> <input /> (Max. File Size is <?php echo ini_get('upload_max_filesize');?>)<br /> <label>Upload File:</label> <input value="Upload File" /> </form> <div style="border: 1px black solid">Status</div> <div>The info during the upload will be displayed here:</div> <iframe src="info.php?ID=<?php echo $id;?>" width="500px" height="350px"></iframe> <div>The actual file upload happens here (and displays info, when it's finished):</div> <iframe width="500px" height="300px"></iframe> </body> </html> |
Tá é um monte de código então vamos as partes simples primeiro:
O primeiro PHP:
$id = md5(microtime() . rand());
Aqui, basicamente eu seto o ID para um valor em tese único. É um random
seed bem básico. Você pode mudar isso pro que quiser, apenas garanta que
o ID vai ser algo meio que único.
O HTML:
<body> <form target="ifr2" action="server.php" enctype="multipart/form-data" method="post"> <input value="<?php echo $id;?>" /> <label>Select File:</label> <input /> (Max. File Size is <?php echo ini_get('upload_max_filesize');?>)<br /> <label>Upload File:</label> <input value="Upload File" /> </form> <div style="border: 1px black solid">Status</div> <div>The info during the upload will be displayed here:</div> <iframe src="info.php?ID=<?php echo $id;?>" width="500px" height="350px"></iframe> <div>The actual file upload happens here (and displays info, when it's finished):</div> <iframe width="500px" height="300px"></iframe> </body>
Sem crise certo? Um form, com action pro server, multipart, post
e um target pro iframe2 (#ifr2). Um input hidden com um ID gerado pelo
PHP, um input file, um submit, alguns labels para sabermos o que é o que
visualmente, um div #status, um iframe #ifr, e um iframe #ifr2. Os
iframes são usados como target para o nosso script depois, mas eles
poderiam ser substituidos por chamadas ajax normais. Finalmente, o
script, onde mora toda a mágica do nosso brinquedo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | var UP = function() { /* private variables */ var ifr = null; var startTime = null; var infoUpdated = 0; var writeStatus = function(text,color) { var statDiv = document.getElementById("status"); if (color == 1 ) { statDiv.style.backgroundColor = "green"; } else if (color == 2 ) { statDiv.style.backgroundColor = "orange"; } else if (color == 3 ) { statDiv.style.backgroundColor = "red"; } else { statDiv.style.backgroundColor = "white"; } statDiv.innerHTML = text; }; return { start: function() { ifr = document.getElementById("ifr"); startTime = new Date(); infoUpdated = 0; this.requestInfo(); }, stop: function(files) { if (typeof files == 'undefined' || files) { var secs = (new Date() - startTime)/1000; var statusText = "Upload succeeded, it took " + secs + " seconds. <br/> "; if (infoUpdated > 0) { writeStatus(statusText + "You had " + infoUpdated + " updates from the progress meter, looks like it's working fine",1); } else { statusText += "BUT there were no progress meter updates<br/> "; if (secs < 5) { writeStatus(statusText + "Your upload was maybe too short, try with a bigger file or a slower connection",2); } else { writeStatus(statusText + "Your upload should have taken long enough to have an progress update. Maybe it really does not work...",3); } } } else { writeStatus('PHP did not report any uploaded file, maybe it was too large, try a smaller one (max. <?php echo ini_get('upload_max_filesize');?>)',3); } startTime = null; }, requestInfo: function() { ifr.src="info.php?ID=<?php echo $id;?>&"+new Date(); }, updateInfo: function(percent, estimatedSeconds) { if (startTime) { if (percent) { infoUpdated++; writeStatus("Download started since " + (new Date() - startTime)/1000 + " seconds. " + Math.floor(percent * 100) + "% done, " + estimatedSeconds + " seconds to go"); } else { writeStatus("Download started since " + (new Date() - startTime)/1000 + " seconds. No progress info yet"); } window.setTimeout("UP.requestInfo()",500); } } } }() |
Criamos um objeto Up que basicamente faz o seguinte: Quando é feito um submit,
rodamos a função start que inicializa um contador de tempo e roda a
função requestInfo. A função requestInfo, abre dentro do #ifr o php
info.php com o ID criado no topo da página. A página info.php gera um
script que chama a função updateInfo. Se o updateinfo, tiver um start,
nos atualizamos o div colocando que ja iniciou o upload mas ainda nao
temos info, se temos um percentual, atualizamos colocando quanto do
upload foi feito. Lembre-se que essas informações vem da página info.php
A função se chama novamente a cada meio segundo. Uma vez concluido o
upload (a página server.php acaba de carregar, é rodado outro script,
que para o relógio e conclui o upload. Vamos para uma rápida explicação
dos outros dois PHPs: info.php
<?php $info = uploadprogress_get_info($_GET['ID']); ?> <html> <head> <script> <?php if ($info !== null) { print "parent.UP.updateInfo(".$info['bytes_uploaded']/$info['bytes_total'].",".$info['est_sec'].")"; } else { print "parent.UP.updateInfo()"; } ?> </script> </head> <body> <pre> <?php print date("c",time())."n"; print $_GET['ID'] ."n"; var_dump($info); ?>