No post passado, comentei que está previsto para o PHP 5.4.0 um novo recurso, que permitirá nativamente controlar o progresso do upload de arquivos. A pedidos, vou postar um exemplo de código que utiliza o novo recurso.
O principal código é em JavaScript. Você pode optar por usar jQuery ou algum framework próprio. Aqui no post, usei JavaScript/DOM puro, apenas para ilustrar.
Para montar a barra de progresso no HTML, utilizei a tag <progress> do HTML 5.
Arquivos
Arquivo index.php
<?php session_start(); $upload_progress_name = ini_get('session.upload_progress.name'); $rand = md5(__FILE__); echo <<<HTML <!DOCTYPE html> <html> <head> <title>Teste</title> <meta name="php.upload_progress_name" content="{$upload_progress_name}" /> <script type="text/javascript" src="script.js"></script> <link rel="stylesheet" type="text/css" href="estilos.css" media="screen" /> </head> <body> <form id="form_upload" method="post" action="recebe.php" enctype="multipart/form-data"> <input type="hidden" name="{$upload_progress_name}" value="{$rand}" /> <div> <label for="arquivo">Arquivo:</label> <input type="file" name="arquivo" id="arquivo" /> </div> <input type="submit" value="Enviar" /> </form> </body> </html> HTML; exit(0);
Arquivo recebe.php
<?php // Simulando um atraso sleep(3); session_start(); echo '<pre>'; var_dump($_POST); echo '</pre>'; echo '<hr />'; echo '<pre>'; var_dump($_FILES); echo '</pre>'; echo '<hr />'; echo '<pre>'; var_dump($_SESSION); echo '</pre>'; exit(0);
Arquivo progresso.php
<?php session_start(); $prefix = ini_get('session.upload_progress.prefix'); $sufix = $_POST[ini_get('session.upload_progress.name')]; $key = $prefix.$sufix; if (isset($_SESSION[$key])) { $content_length = $_SESSION[$key]['content_length']; $bytes_processed = $_SESSION[$key]['bytes_processed']; $done = $_SESSION[$key]['done'] ? 1 : 0; $percent = intval($bytes_processed * 100 / $content_length); } else { $content_length = 0; $bytes_processed = 0; $done = 0; $percent = 0; } // Se terminou o upload: liberar memoria da sessao if ($done) { unset($_SESSION[$key]); } header('Content-Type: text/xml; charset=UTF-8'); echo <<<XML <?xml version="1.0" encoding="UTF-8" ?> <progress> <content_length>{$content_length}</content_length> <bytes_processed>{$bytes_processed}</bytes_processed> <percent>{$percent}</percent> <done>{$done}</done> </progress> XML; exit(0);
Arquivo script.js
if (window.addEventListener) { window.addEventListener("load", prepare_upload_forms, false); } /** * Funcao para preparar os formularios para o controle de progresso de upload. * @return void */ function prepare_upload_forms() { var upload_progress_name = get_upload_progress_name(); if (!upload_progress_name) { return; } var len = document.forms.length; for (var i = 0; i < len; i++) { var form = document.forms.item(i); var input = get_upload_progress(form, upload_progress_name); if (input) { if (form.addEventListener) { form.addEventListener("submit", open_progress_bar, false); } } } } /** * Obtem o nome usado pelo PHP para controle de progresso * @return string */ function get_upload_progress_name() { var vt_meta = document.getElementsByTagName("meta"); var len = vt_meta.length; for (var i = 0; i < len; i++) { var meta = vt_meta.item(i); if (meta.getAttribute("name") == "php.upload_progress_name") { return meta.getAttribute("content"); } } return false; } /** * Obtem o input que define que o formulario tera o progresso de upload controlado. * @param FORM form Formulario. * @param string upload_progress_name Nome reservado para indicar controle de progresso pelo PHP. * @return INPUT || bool */ function get_upload_progress(form, upload_progress_name) { var vt_input = form.getElementsByTagName("input"); var len = vt_input.length; for (var i = 0; i < len; i++) { var input = vt_input.item(i); if (input.getAttribute("name") == upload_progress_name) { return input; } } return false; } /** * Instancia um XML HTTP Request. * @return XMLHttpRequest || bool */ function get_xhr() { return new XMLHttpRequest(); } /** * Abre a caixa de progresso do formulario de upload. */ function open_progress_bar(event) { var div = document.createElement("div"); div.className = "progress"; { var label = document.createElement("span"); label.appendChild(document.createTextNode("Progresso:")); var progress = document.createElement("progress"); progress.id = "upload_progress"; progress.setAttribute("value", "0"); progress.setAttribute("max", "100"); progress.appendChild(document.createTextNode("0/0 (0%)")); div.appendChild(label); div.appendChild(progress); } this.appendChild(div); var upload_progress_name = get_upload_progress_name(); var input = get_upload_progress(this, upload_progress_name) var upload_id = input.getAttribute("value"); window.setTimeout("update_progress('" + upload_id + "')", 100); return true; } /** * Realiza uma requisicao assincrona para consultar o andamento do Upload. * @param string upload_id */ function update_progress(upload_id) { var url = window.location.href; var vt = url.split('/'); vt.pop(); url = vt.join('/') + '/progresso.php'; var upload_progress_name = get_upload_progress_name(); var dados = encodeURIComponent(upload_progress_name) + "=" + encodeURIComponent(upload_id); var xhr = get_xhr(); xhr.upload_id = upload_id; xhr.open("POST", url, false); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.setRequestHeader("Content-Length", dados.length); xhr.setRequestHeader("Connection", "close"); xhr.onreadystatechange = ready_state_change; xhr.send(dados); } /** * Evento quando muda o estado da requisicao Ajax */ function ready_state_change() { if (this.readyState == 4) { if (this.status == 200) { var xml = this.responseXML; var percent = xml.getElementsByTagName("percent").item(0).textContent; var content_length = xml.getElementsByTagName("content_length").item(0).textContent; var bytes_processed = xml.getElementsByTagName("bytes_processed").item(0).textContent; var done = xml.getElementsByTagName("done").item(0).textContent; var progress = document.getElementById("upload_progress"); progress.setAttribute("value", percent); var texto_antigo = progress.firstChild var texto_novo = document.createTextNode(bytes_processed + "/" + content_length + " (" + percent + "%)"); progress.replaceChild(texto_novo, texto_antigo); if (done == "0") { window.setTimeout("update_progress('" + this.upload_id+ "')", 1000); } } } return true; }
Arquivo estilos.css
.progress { background-color: #303030; border: 1px outset #303030; color: #EEEEEE; display: block; width: 400px; padding: 5px; position: fixed; left: 0; top: 0; }
Observações
Para este script funcionar, é preciso que o PHP esteja configurado adequadamente e, se você estiver rodando o script localmente, também vai precisar de um arquivo bem grande para ver a barra ser preenchida aos poucos. Eu testei com um arquivo de 1.7GB e usei as seguintes configurações no php.ini:
file_uploads = On upload_max_filesize = 2000M max_file_uploads = 20 post_max_size = 2000M session.upload_progress.enabled = On session.upload_progress.cleanup = Off session.upload_progress.prefix = "upload_progress_" session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" session.upload_progress.freq = "1%" session.upload_progress.min_freq = "1"
Desabilitei session.upload_progress.cleanup pois o próprio script de progresso limpa a sessão quando chega a 100% (veja o código acima). Você pode optar por fazer um garbage collector personalizado. Por exemplo, sempre apagar as posições da sessão que foram iniciadas a mais de 10 minutos, por exemplo.
37 comentários
Comigo não funcionou...
Mas esse exemplo funcionou blz:
http://blog.thiagobelem.net/upload-de-arquivos-com-php/
Eu só ainda não sei como fazer o PROGRESSO, mas logo logo eu chego lá
Olá, Anônimo
Como eu coloquei no post, este recurso está disponível apenas para o PHP 5.4, que foi lançado oficialmente ontem. Você experimentou o código nesta versão?
O objetivo do post não era mostrar como fazer o upload de arquivos via PHP e sim mostrar como implementar uma barra de progresso do upload, que é algo complementar.
Até
Esse cientista da computação ñ sabe é nd!
Olá, Anônimo
Agradeço pela crítica, embora ela soe um tanto ofensiva. Caso ela tenha sido motivada por alguma informação incorreta no post, seria muito legal se você postasse isso nos comentários e eu corrigiria sem problemas.
Ou então, se tiver sugestões de como melhorar o blog, também aceito.
Olá Rubens,
Bacana seu blog. Parabéns!
Você acaso conhece alguma script de barra de progresso para inserção de dados no mysql via php?
Valeu!
Vivendo a Palavra: é possível criar uma barra de progresso sim. Eu não conheço algum pronto.
A idéia é a seguinte: você vai requisitar a ação via Ajax e montar uma barra de progresso dinamicamente com javascript. O servidor recebe a requisição e inicia o processo, guardando seu percentual concluído como 0%. Depois, você realiza requisições Ajax pelo cliente periodicamente para saber o percentual concluído e atualiza dinamicamente a barra de progresso. O servidor recebe estas requisições e devolve o progresso. Quando chegar a 100%, você sabe que terminou.
E o controle de tudo isso no servidor pode ser feito em BD ou em arquivo temporário, para cada requisição.
Talvez eu faça um post sobre isso no futuro.
Valeu Rubens,
Estou buscando uma solução para implementar em um projeto. Insiro muitos registros na hora da instalação e é interessante posicionar o usuário do andamento do processo.
Fica na Paz!
Rubens eu ja tenho um script para upload de arquivos, mas eu custumo fazer uploads de arquivos bem pesados para o meu site,portanto eu gostaria de saber se há como implementar uma barra de progresso nele.
Olá, HDL.
Creio que seja perfeitamente possível, caso você já esteja utilizando o PHP 5.4.
Conforme mostrado do post, as mudanças necessárias num script convencional de upload não são conflitantes.
Para mais detalhes, veja o post que apresenta os conceitos desse novo recurso: http://rubsphp.blogspot.com.br/2011/11/controle-do-progresso-de-upload.html
Rubens acho que com um diagrama ficaria mais fácil de compreender como realmente funciona o fluxo, seria bem legal um diagrama na postagem.
Olá, Josue.
No post anterior expliquei como funciona. Neste post, apenas coloquei a implementação.
http://rubsphp.blogspot.com.br/2011/11/controle-do-progresso-de-upload.html
Olá Rubens,
eu realizei todo o fluxo, configurei o php. Mas no script
$key = ini_get("session.upload_progress.prefix") . $_POST[ini_get("session.upload_progress.name")];
var_dump($_SESSION[$key]);
ele me retorna null, não sei o que fazer! Você pode me ajudar?
Igor.
Olá, Igor.
Certifique-se de que esteja utilizando o PHP 5.4 ou superior.
Se estiver, dê um dump na $_SESSION para ver se está guardando o progresso em algum índice.
Oi Rubens,
é superior ao 5.4, não está guardando nada na $_SESSION
Igor.
O valor retornado da SESSION é null, vc sabe o que é? Pode me ajudar.
Obrigado,
Igor.
Então confira se a diretiva de configuração session.upload_progress.enabled esteja habilitada e que você está gerando o campo hidden no formulário com o nome correto.
A documentação oficial está no link: http://php.net/manual/en/session.upload-progress.php
Dê uma olhada se seguiu tudo corretamente.
Igor, faz o seguinte: me manda um e-mail (rubs33@gmail.com) e eu te mando o código completo mais as configurações do php.ini. Aqui está funcionando.
Enviei o e-mail,
Obrigado.
Igor.
Rubens pelo post parabéns consegui sim mais como posso editar o tamanha da barra de progresso os botoes e etc...
Olá, tudo sobre tecnologia.
Neste exemplo, coloquei a barra de progresso em um DIV fixo no canto superior direito, com a largura de 400px.
Para ajustar, basta editar o arquivo CSS ao seu gosto.
Brother, é o seguinte.
Sou novo nesse ramo de PHP e JavaScript, mais consigo entender algumas coisas básica, me deparei com um problema... " Criei um formulário de Upload, envia os arquivos para a pasta especificada, só que quero que me avise por e-mail que eu recebi um arquivo no FTP entende, só que não consegui."
Me ajuda ai.
By: Anderson - Bahia
Olá, Anderson
Para enviar um e-mail, você pode usar a função "mail" do PHP.
http://php.net/manual/en/function.mail.php
Ou pode usar uma classe que tenha recursos adicionais, como enviar e-mail com anexo, etc. Por exemplo: phpmailer
Para isso, você também precisa configurar o servidor de envio de e-mail (smtp).
Vlw, mais axo que vc não entendeu.
é o Seguinte. Fiz esse Código Upload em PHP.
Código
$baixar = 'ftp/';
$baixar_arquivo = $baixar . $_FILES['arquivo']['name'];
if (move_uploaded_file($_FILES['arquivo']['tmp_name'], $baixar_arquivo)){
echo "Arquivo Enviado";}
else {echo "Arquivo não enviado";
FIM
E agora preciso implementar o código para enviar o email de aviso que recebir um arquivo no meu FTP.
Ajuda ai.
Olá, Anderson
Acho que entendi o que você quer: enviar um e-mail automaticamente quando fizer o upload. Sugeri duas formas: com a função mail (do próprio PHP) ou baixando alguma biblioteca que faça esse serviço, como a classe phpmailer.
Você só precisa estudar as duas formas e usar uma delas dentro de seu "if". Já coloquei o link da função "mail", que explica como usá-la.
Para usar o phpmailer, vou te passar o link do blog do thiago belem, que tem um post sobre o assunto:
http://blog.thiagobelem.net/enviar-e-mails-pelo-php-usando-o-phpmailer/
Novamente, recomendo que leia sobre servidor de envio de e-mail (dê uma pesquisada sobre smtp, postfix, etc).
valeu cara!
Me ajudou matar a curiosidade quando li sobre a atualização do php 5.4 resolvi querer ver como era isso...
Olá, muito bom o seu post, é o seguinte eu sou um pouco leigo no assunto, estou aprendendo, tenho um site que se faz upload, não consigo emplementar uma barra de progresso enquanto o arquivo do usuário é enviado para o servidor, são todos esses códigos que vc colocou mesmo ou só parte dele? Agradeço!!!
Olá, Anônimo
Infelizmente precisa de todos estes arquivos. Basta copiar e colar cada um com o respectivo nome. Mas lembre-se que precisa ser no PHP versão 5.4 ou posterior. Para saber qual você está usando, basta fazer um script que exiba o valor da constante PHP_VERSION:
echo PHP_VERSION;
Rubens, bom dia. Estou tentando implementar uma rotina da barra de progresso com banco de dados postgress e não esta dando certo, você teria alguma coisa desse jeito, uso o banco de dados para enviar os dados de quem enviou o arquivo e algumas outras informações.
Grato,
Dário
Olá, Dário
O controle sobre a barra de progresso independe do recurso que você usa para armazenar os arquivos. Não faz diferença se você guarda em PostgreSQL, MySQL, ou apenas copia os arquivos para um outro diretório. O controle de progresso de upload diz respeito à quantidade de bytes que foram transferidos dos arquivos da máquina do cliente (navegador) para o servidor.
Sugiro que, inicialmente, experimente copiar o conteúdo dos arquivos mostrados neste artigo, ajustar as configurações do PHP e testar para ver se funciona. Caso funcione, basta adaptá-los para a sua realidade, ou seja, alterar principalmente o arquivo "recebe.php" para salvar os dados onde você deseja.
Olá quando testo o código no "xampp" aparece um erro de sintaxe -> Parse error: syntax error, unexpected 'var' (T_VAR)
exatamente na linha contendo -> var upload_progress_name = get_upload_progress_name();
saberia oque pode ser agradeço a ajuda abraço!!!
Olá, Anônimo
O arquivo que contém esse trecho de código é JavaScript e não PHP. E essa mensagem que você mostrou é um erro de sintaxe de código PHP. Portanto, você deve tá tentando executar um JavaScript com PHP, que não dá certo. Talvez você salvou o arquivo com extensão ".php" ou então tenha colocado o trecho de código junto com o código PHP, mas são coisas separadas.
Obrigado pela ajuda Rubens você estava absolutamente certo. Como ainda estou aprendendo a programar cometo esses erros bobos, caso tenha alguma dica pra que eu possa melhorar, na faculdade eu só aprendi a manipular as sintaxes fazendo exercícios nunca fiz projetos ou nada do tipo agora que comecei a fazer um estágio que percebo que é bem diferente. Meu chefe pediu pra eu fazer uma barra de upload pro enviar arquivos pro banco de dados. Consegui graças ao seu Blog mais uma vez agradeço pela ajuda!
Amigo gostei do seu código eu ainda estou aprendendo sobre PHP, se puder me ajudar com algumas uma dúvidas, eu gostaria de saber qual parte do código específica para qual pasta esta sendo enviada os arquivos upados e sem tem a possibilidade de selecionar mais de um arquivo para upload se tem em qual parte do código ele entraria. Também gostaria de saber se os três códigos em PHP(index, recebe, e progresso) podem estar no mesmo documento. Grato!
Antes de mais nada, PHP é algo novo para mim, então surgiu uma dúvida (desculpe caso seja algo tolo).
Salvei todas as páginas (conforme artigo), no lugar de sleep(3) na página recebe.php, inseri o meu código de upload do arquivo, porém a barra de progresso fica estática.
Sabe o que pode estar acontecendo? Creio que o erro esteja no arquivo progresso.php.
Agradeço desde já.
Olá, Rafael
Além dos arquivos do artigo, você também precisa configurar o PHP adequadamente (veja no final do artigo).
Provavelmente sua diretiva file_uploads não está ativa.
boa tarde, gostei muito do seu código, porém não aparece a contagem do percentual, exibe sim uma barra horizontal, que já é alguma coisa, porém, estática, sem andamento de carregamento.
Postar um comentário
Nota: fique a vontade para expressar o que achou deste artigo ou do blog.
Dica: para acompanhar as respostas, acesse com uma conta do Google e marque a opção "Notifique-me".
Atenção: o blogger não permite inclusão de tags nos comentários, por isso, use algum site externo para postar seu código com dúvidas e deixe o link aqui. Exemplo: pastebin.com