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.
Execute “pecl install uploadprogress”, e adicione “extension=uploadprogress.so” ao seu arquivo php.ini .
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
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:
<input type="hidden"
name="UPLOAD_IDENTIFIER"
value="upld<?php md5(time());?>" />
- 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
💬 Comentários (21)
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,
[quote]uploadprogress.file.filename_template = /caminho/para/algum_arquivo_%s.txt Onde devo mudar este caminho no php.ini?[/quote]
Sim, isso você muda no php ini, ou usa a função ini_set em seu aplicativo.
[quote]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?[/quote]
Esta função deve estar em uma resposta ajax que será tratada pela interface.
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…
Olá!
Parece que está faltando o GCC, o compilador de linguagem C da GNU.
O comando abaixo resolve esta dependência em específico:
[code class=“bash”] yum install gcc [/code]
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,
Olá Lourenzo,
Agradeço pela atenção.
Consegui instalar normalmente seguindo as recomendações deste blog:
http://freestylesystems.co.uk/blog/installng-pecl-uploadprogress-extension-drupal-filefield-module
Parabéns pelo artigo, vi no blog da KingHost. :)
Abraços, Leonardo Cesar Teixeira
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!
Legal, tinha mesmo esquecido dessa possibilidade.
Inclusive aqui no meu mac eu tive que fazer isso para funcionar o GD…
Olá!
Eu cito um exemplo bem simples no post, mostrando como fazer.
Neste artigo: http://ajaxian.com/archives/asynchronous-file-upload-with-ajax-progress-bar-in-php
Tem uma explicação mais elaborada e um exemplo para download.
O artigo está em inglês.
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:
agora você só precisa ficar passar o $id_up via GET para um arquivo de código que tenha o seguinte:
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!
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á! 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,
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
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