Progresso de Upload com PHP 5.2+
O desafio é criar uma barra de monitoramento de progresso para uploads de arquivo, quando se está utilizando AJAX.
Pode até se achar que isso é frescura, mas no caso de envio de arquivos grandes, isso pode ser bastante útil.
Há muita gente na web dizendo que é impossível fazer isso apenas com PHP. Até certo ponto isso é verdade, pois até pouco tempo, o PHP só obtinha acesso a REQUESTs completos, e o progresso de upload, obviamente, só pode ser medido durante o REQUEST.
A solução encontrada foi usar Perl em paralelo, num bem-bolado que pode trazer problemas. O fornecido script CGI feito em Perl recebe o POST, e consegue acessar os dados do REQUEST enquanto ele está em andamento.
Exemplo: http://br.php.net/features.file-upload (Em inglês)
Isso seria a única saída para o problema no caso de se usar uma versão do PHP inferior à 5.2. Isso porque, da versão 5.2 em diante, o PHP suporta um gancho que pode ser usado para lidar com o progresso do upload. Você pode usar uma extensão PECL já existente (uploadprogress) para mostrar um medidor do progresso de um upload.
Tendo em vista que a documentação para essa extensão é escassa, aqui vai uma simples receita de bolo.
1) Execute "pecl install uploadprogress", e adicione "extension=uploadprogress.so" ao seu arquivo php.ini .
2) Diga à extensão onde armazenar temporariamente as informações sobre cada upload. Por padrão, isso será guardado em "/tmp/upt_%s.txt" (onde %s deve ser substituído pela variável UPLOAD_IDENTIFIER, como será descrito abaixo). Você pode mudar isso na através da seguinte linha no arquivo de configuração: uploadprogress.file.filename_template = /caminho/para/algum_arquivo_%s.txt
Você deve adicionar apenas um '%s', ou a coisa toda irá falhar
3) Adicione um campo oculto bem no início do seu formulário de upload (isso é importante) , com o nome de UPLOAD_IDENTIFIER. O valor para esse campo deve combinar com a expressão regular "^[A-Za-z0-9_.-=]{1,64}$" , ou seja, possuir de 1 a 64 caracteres alfanuméricos, sendo que as letras podem ser maiúsculas ou minúsculas. Além disso, o valor deve ser único para cada upload.
Exemplo:
4) Agora vem a parte da diversão... Mostrar a barra de progresso.
Vou descrever uma maneira bem simples de fazer isso, deixando bem claro que é possível fazer isso com muito mais requinte.
Quando o formulário for submetido, abra um popup aproveitando a ação do usuário (o click pode ajudar seu popup a não ser bloqueado) para mostrar o progresso. Essa janela deve ser atualizada repetidamente de poucos em poucos segundos, chamando um script que irá tratar os dados e exibir as informações, e gerar um medidor.
Esse script chama a função uploadprogress_get_info($id), onde $id é o valor do campo UPLOAD_IDENTIFIER do seu formulário. A função retornará falso caso não haja um upload relacionado, ou um array de informações sobre o upload. O array contém:
- time_start
- Data/Hora do início do upload (no mesmo formato da função time()).
- time_last
- Data/Hora da última atualização do progress de upload.
- speed_average
- Velocidade média. (bytes / segundo)
- speed_last
- Última velocidade medida. (bytes / segundo)
- bytes_uploaded
- Número de bytes recebidos pelo servidor até o momento.
- bytes_total
- O valor do cabeçalho HTTP "
Content-Length" enviado pelo navegador. - files_uploaded
- Número de arquivos já recebidos pelo servidor.
- est_sec
- Número estimado de segundos restantes para o término do processo de upload.
O valor speed_average é medido com base no número de bytes obtidos pelo servidor desde o início do upload, enquanto speed_last é baseado no número de bytes enviados desde a última atualização no progresso do upload. A informação sobre o progresso é atualizada cada vez que o PHP obtêm mais dados do cliente, então speed_last pode não ser muito preciso.
Nota 1) O valor bytes_total NÃO é reflexo do tamanho real do arquivo, mas sim do tamanho do REQUEST POST, que pode ser maior que o tamanho real do arquivo transferido.
Nota 2) Esse módulo realmente detecta apenas quanto do formulário com método POST foi recebido pelo servidor, e mantém uma contagem de quantas variáveis POST do tipo 'file' vão sendo encontradas. Então quando forem enviados vários arquivos em um mesmo formulário, não é possível fazer uma medição de progresso para cada arquivo, mas é possível obter a contagem de quantos arquivos já foram completamente transferidos.
Fonte: Documentação online do PHP, em um dos comentários:
http://br.php.net/manual/pt_BR/features.file-upload.php#71564















Comments
Cara! Muito bom!!! Eu estava fazendo uma lingüiça com php e várias bibliotecas Java para fazer essa barra maldita hehehehe. Parabéns!
De qualquer forma ainda vou ter que pesquisar mais sobre isso para fazer o formulário prático. Vou assinar o Feed e vou ficar na expectativa de um exemplo desta função. Valeu !!!!
Olá parabens pelo artigo, realmente este tema é muito escasso em português.
Estou tentanto implementar esta barra de progressão num site que estou desenvolvendo mais estou esbarrando em algumas dúvidas:
No item 2 você fala para mudar o caminho para:
uploadprogress.file.filename_template = /caminho/para/algum_arquivo_%s.txt
Onde devo mudar este caminho no php.ini?
Você fala mais abaixo de chamar a função: uploadprogress_get_info($id), não encontrei esta função no meu código, onde ela deve ficar?
Grato,
Onde devo mudar este caminho no php.ini?
Sim, isso você muda no php ini, ou usa a função ini_set em seu aplicativo.
Esta função deve estar em uma resposta ajax que será tratada pela interface.
Lourenzo Ferreira
Onde se deve executar "pecl install uploadprogress"?
Olá!
O comando deve ser executado no terminal bash, no caso de ser Windows eu imagino que no emulador de DOS, vulgo cmd. Nesse caso pode ser necessário configurar o PATH do Windows para que este execute o comando...
Lourenzo Ferreira
Muito obrigado! vou usar este artigo para instalar no meu servidor local (de testes) a extensão uploadprogress.
Olá Lourenzo,
Estou tentando instalar o uploadprogress no meu servidor dedicado mas está dando o seguinte erro:
root@whl0001 [~]# pecl install uploadprogress
downloading uploadprogress-1.0.1.tgz ...
Starting to download uploadprogress-1.0.1.tgz (8,536 bytes)
.....done: 8,536 bytes
4 source files, building
running: phpize
Configuring for:
PHP Api Version: 20041225
Zend Module Api No: 20060613
Zend Extension Api No: 220060519
building in /var/tmp/pear-build-root/uploadprogress-1.0.1
running: /root/tmp/pear/uploadprogress/configure
checking for egrep... grep -E
checking for a sed that does not truncate output... /bin/sed
checking for cc... cc
checking for C compiler default output file name... a.out
checking whether the C compiler works... configure: error: cannot run C compiled programs.
If you meant to cross compile, use `--host'.
See `config.log' for more details.
ERROR: `/root/tmp/pear/uploadprogress/configure' failed
root@whl0001 [~]#
Sabe o que pode ser?
No meu servidor dedicado possuo o CentOS 5.3, PHP 5.2.10 e WHM/cPanel 11.24.2.
Abraços!
Olá!
Parece que está faltando o GCC, o compilador de linguagem C da GNU.
O comando abaixo resolve esta dependência em específico:
Mas é provável que surjam outras dependências, talvez seja mais interessante procurar uma forma de instalar a extensão utilizando o yum, que verificará todas as dependências automaticamente.
Att,
Lourenzo Ferreira
Olá Lourenzo,
Agradeço pela atenção.
Consegui instalar normalmente seguindo as recomendações deste blog:
http://freestylesystems.co.uk/blog/installng-pecl-uploadprogress-extensi...
Parabéns pelo artigo, vi no blog da KingHost. :)
Abraços,
Leonardo Cesar Teixeira
Legal, tinha mesmo esquecido dessa possibilidade.
Inclusive aqui no meu mac eu tive que fazer isso para funcionar o GD...
Lourenzo Ferreira
amigo, existe algum exemplo para leigo igual a eu ... ?? Procurei no site http://br.php.net/features.file-upload enão entendi e nem consegui achar onde nem como posso utilizar a barra de progresso do php. Ficaria muito grato se pudesse me ajudar.
Olá!
Eu cito um exemplo bem simples no post, mostrando como fazer.
Neste artigo: http://ajaxian.com/archives/asynchronous-file-upload-with-ajax-progress-...
Tem uma explicação mais elaborada e um exemplo para download.
O artigo está em inglês.
Lourenzo Ferreira
Olá Lourenzo, fiquei muito feliz pela resposta.
Fiz alguns testes, perdi algumas horas e nada.
Achei esse arquivo http://t.wits.sg/2008/06/25/howto-php-and-jquery-upload-progress-bar/ fiz como está ai e nada ...
Rapaz, desculpa a pergunta, mas qual a possibilidade de me oferecer um suporte, para fazer essa barra de upload funcionar lá no servidor da King Host ?
Reforço meus agradecimentos.
Att/ Renato
eu consegui fazer funcionar na kinghost o upload_progress...
bom.. a princípio vc vai ter que ir no painel de controle e desativar o MODSECURITY..
exemplo de formulário que vai enviar o POST:
<?php
// identificador do upload..
$id_up = md5(time());
// se for na internet (kinghost)
if(function_exists("apc_fetch")){
echo '';
}else{
// localmente (ubuntu)
echo '';
}
?>
selecione o arquivo
agora você só precisa ficar passar o $id_up via GET para um arquivo de código que tenha o seguinte:
<?php
// se for na internet (kinghost)
if(function_exists("apc_fetch")){
$upload = apc_fetch('upload_'.$_GET[id]);
if($upload){
if ($upload[done]){
$percent = 100;
}else if ($upload[total] == 0){
$percent = 0;
}else{
$percent = $upload[current] / $upload[total] * 100;
}
$atual = $upload[current];
$total = $upload[total];
}else{
#echo 'Sem informações ainda..';
}
}else{
// localmente (ubuntu)
$upload = uploadprogress_get_info($_GET[id]);
if($upload){
$percent = $upload[bytes_uploaded] / $upload[bytes_total] * 100;
$atual = $upload[bytes_uploaded];
$total = $upload[bytes_total];
}else{
#echo 'Sem informações ainda..';
}
}
// da o feedback
if($percent > 0){
// tranforma para de bytes para Kbytes
$atual = (int)($atual/1024);
$total = (int)($total/1024);
// se for mais que 1mega, mostra em MB, senão mantém em KB
if($atual > 1024){
$atual = (int)($atual/1024).'Mb';
}else{
$atual .= 'Kb';
}
if($total > 1024){
$total = (int)($total/1024).'Mb';
}else{
$total .= 'Kb';
}
echo ''.(int)$percent.'% ('.$atual.' de '.$total.')';
}
#print_r($upload);
?>
você vai ter que usar no mínimo um pouco de javascript.. pra fazer funcionar tudo automaticamente.. (a chama do arquivo que vai ver o andamento de upload)
E aí João, parabéns, você conseguiu...
..Então, eu também hospedo na Kinhost, e não consegui fazer funcionar o upload_progress.. , desabilitei o mod_security etc.. diz que tanto a função apc_fecth() quanto a uploadprogress_get_info() não existem, pode me dar alguma sugestão?
msn: raruol3@hotmail.com
Abraço!
Olá! Tanto a função uploadprogress_get_info() quando a apc_fetch() do Advanced PHP Cache podem rastrear o andamento dos uploads atualmente.
No caso do KingHost é bem provável que não tenham APC (ele deixa tudo muito rápido, mas custa memória RAM), mas você pode pedir que eles ensinem como instalar/utilizar o uploadprogress (extensão do PHP) em seu site.
Att,
Lourenzo Ferreira
Eu quero usar no seguinte site:
www.gigantesdanatureza.com.br
acessem em breve, abraços
Opa.. bah.. agora que vi.. uma parte do código (HTML) que eu postei na mensagem anterior o blog comeu... (ali onde diz selecione o arquivo)...
bah.. se ele diz que não existe a função apc_fetch, eu não sei o que te dizer. Você deve entrar em contato com o suporte e informar sua situação, pedir para verificarem se está instalado o recurso no servidor.
a função uploadprogress_get_info, pelo que me lembro existe (no meu servidor), mas não funciona como deveria, e isto acontece por que o servidor é red hat.. e não há nenhuma informação sobre isso na internet... aparentemente..
bom.. abre um ticket de assistência... qualquer coisa me manda e-mail: psicqs@yahoo.com.br
Olá!
Abaixo do formulário de comentário há um informativo que lista as tags HTML permitidas em comentários.
Esta restrição ajuda a proteger os leitores de código potencialmente danoso.
apc_fetch é uma função do APC, Advanced PHP Cache, que agora é nativo do PHP. Ela pode ser usada para acompanhar o progresso de uploads também.
Abs
Lourenzo Ferreira
Opa! Valew João e Lourenzo...
Obrigado pelas respostas...
Eu vou entrar em contato com o suporte da KingHost, quem sabe eles solucionem meu problema.
Abraços
http://raruol.wordpress.com
Parabéns pelo trabalho realizado no blog.
Excelente quarta,
Marceli
Post new comment