Meio que dando continuidade ao post “Listando fotos de um diretório com PHP”, hoje trago para você uma pequena aplicação web para upload de imagens utilizando a nova API File Reader do HTML5 juntamente com a nova API Drag’n Drop.
Esta aplicação web terá uma pré-visualização da imagem enviada e uma barra de progresso de upload. Neste exemplo a aplicação web fará o armazenamento das imagens em um diretório configurado, mas nada impede você de melhorar ainda mais o código.
Fazer o upload de arquivo usando HTML5 é uma combinação de 3 tecnologias: a API File Reader, a API Drag’n Drop e o nosso querido Ajax. Aqui temos uma descrição do processo:
- O usuário ‘larga’ a imagem no local indicado arrastando o arquivo de um diretório do seu computador. Os navegadores que tiverem suporte à API Drag’n Drop dispararão um evento e a aplicação web exibirá uma lista das imagens ‘largadas’ para o upload;
- Com a API File Reader, a aplicação web ‘lerá’ os arquivos da lista como dados binários e armazenará a informação em memória;
- Então usaremos o método sendAsBinary do objeto XMLHttpRequest e será enviado o arquivo para o servidor; Parece complicado, mas graças ao jQuery e o seu plugin Filedrop a customização necessária para tudo funcionar será bem pequena.
ATENÇÃO:Essa aplicação foi testada apenas nas últimas versões do Chrome e do Firefox e funciona perfeitamente. Se quiser testar em outros navegadores, fique a vontade e comente o seu resultado.
- Mãos a obra !
O HTML
Nossa página principal será bem simples. Um título identificando a aplicação web e a área de ‘drop’ dos arquivos.
<!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="utf-8" /> <title>Upload de arquivos via Drag and Drop com HTML5, jQuery e PHP</title> <link rel="stylesheet" href="css/styles.css" /> <script src="js/jquery-1.8.3.min.js"></script> <script src="js/jquery.filedrop.js"></script> <script src="js/script.js"></script> </head> <body> <header> <h1>Upload de arquivos - HTML5, jQuery e PHP</h1> </header> <section> <div id="dropbox"> <span class="message"> Arraste suas imagens aqui para upload. <br /> <i>(Elas ficarão visíveis somente para você)</i> </span> </div> </section> </body> </html>
O elemento #dropbox é o responsável por ‘receber’ os arquivos e é dele que o nosso script de upload vai ler a lista de arquivos. A mensagem existente será atualizada caso haja algum erro no processo (por exemplo, o navegador não suportar o upload de arquivos via HTML5). Quando você ‘largar’ o arquivo no #dropbox, o nosso código jQuery irá adicionar o seguinte código:
<div class="preview"> <span class="imageHolder"> <img /> <span class="uploaded"></span> </span> <div class="progressHolder"> <div class="progress"></div> </div> </div>
Este código exibe a miniatura da imagem e a barra de progresso do upload.
O Javascript
Toda a funcionalidade de transferência de arquivos é tratada pelo plugin Filedrop, mas temos que ‘chamá-lo’ e passar alguns parâmetros para o seu correto funcionamento. O nosso script, além de parametrizar o plugin Filedrop cria a miniatura da imagem que será transferida, a barra de progresso do upload e ao final insere uma imagem de conclusão da transferência.
js/script.js
$(function(){ var dropbox = $('#dropbox'), message = $('.message', dropbox) dropbox.filedrop({ paramname:'pic', maxfilesize: 2, url: 'upload.php', dragOver:function(){ $('#dropbox').addClass('over'); }, uploadFinished:function(i,file,response){ $.data(file).addClass('done'); }, error: function(err, file) { switch(err) { case 'BrowserNotSupported': showMessage('Seu browser não suporta o upload via HTML5!'); break; case 'TooManyFiles': alert('Muitos arquivos! Por favor, selecione no máximo 5 imagens! (configurável)'); break; case 'FileTooLarge': alert(file.name+' é muito grande! Por favor, selecione arquivos de até 2mb (configurável).'); break; default: break; } }, beforeEach: function(file){ if(!file.type.match(/^image\//)){ alert('Apenas imagens são permitidas'); return false; } }, uploadStarted:function(i, file, len){ createImage(file); }, progressUpdated: function(i, file, progress) { $.data(file).find('.progress').width(progress); } }); var template = '<div class="preview">'+ '<span class="imageHolder">'+ '<img />'+ '<span class="uploaded"></span>'+ '</span>'+ '<div class="progressHolder">'+ '<div class="progress"></div>'+ '</div>'+ '</div>'; function createImage(file){ var preview = $(template), image = $('img', preview); var reader = new FileReader(); image.width = 100; image.height = 100; reader.onload = function(e){ image.attr('src',e.target.result); }; reader.readAsDataURL(file); message.hide(); preview.appendTo(dropbox); $.data(file,preview); } function showMessage(msg){ message.html(msg); } });
Com este código, toda imagem válida que for coloca no #dropbox será enviada ao upload.php que será responsável pela ‘mágica’.
O PHP
O código PHP não é diferente do que você está acostumado a criar para fazer uploads através de formulários comuns.
upload.php
<?php $diretorio = "./uploads/"; $arq_perm = array('jpg','jpeg','png','gif'); if(strtolower($_SERVER['REQUEST_METHOD']) != 'post'){ exit_status('Erro! Método HTTP errado!'); } if(array_key_exists('pic',$_FILES) && $_FILES['pic']['error'] == 0 ){ $imagem = $_FILES['pic']; if(!in_array(get_extension($imagem['name']),$arq_perm)){ exit_status('Apenas arquivos dos tipos '.implode(',',$arq_perm).' são permitidos!'); } if(move_uploaded_file($imagem['tmp_name'], $diretorio.$imagem['name'])){ exit_status('Upload concluído com sucesso!'); } } exit_status('Aconteceu algum problema com o upload!'); function exit_status($str){ echo json_encode(array('status'=>$str)); exit; } function get_extension($file_name){ $ext = explode('.', $file_name); $ext = array_pop($ext); return strtolower($ext); } ?>
Esse script verifica o método HTTP utilizado para enviar os arquivos e também a extensão dos arquivos enviados. Na página de demonstração os arquivos não são enviados a nenhum diretório do meu servidor.
O CSS
A parte principal da nossa aplicação web de upload de arquivos está pronta. Vamos agora deixá-la um pouco mais apresentável. Claro que não tive muito trabalho para criar este CSS, pois isto não era o foco desse post. Fiquem à vontade para criar outras interfaces e postem nos comentários os resultados.
css/styles.css
* { margin:0; padding:0; } html{ min-height:100%; position:relative; } body{ margin: auto; min-height:600px; font:14px 'Helvetica',Arial, sans-serif; width: 60%; } header{ display:block; } header{ margin: 10px; position: relative; } h1{ padding: 5px; text-align: center; } #dropbox{ background: #444; border: 10px solid #222; border-radius: 20px; color: #fff; margin:auto; min-height: 290px; overflow: hidden; padding-bottom: 40px; width: 90%; } #dropbox .message{ font-size: 11px; text-align: center; padding-top:130px; display: block; } #dropbox .message i{ color:#ccc; font-size:10px; } #dropbox .botao { font-size: 11px; text-align: center; display: block; margin: auto; color: #fff; border: 1px solid #fff; border-radius: 3px; width: 110px; cursor: pointer; } #dropbox .preview{ width:245px; height: 215px; float:left; margin: 55px 0 0 60px; position: relative; text-align: center; } #dropbox .preview img{ max-width: 240px; max-height:180px; border:3px solid #fff; display: block; box-shadow:0 0 2px #000; } #dropbox .imageHolder{ display: inline-block; position:relative; } #dropbox .uploaded{ position: absolute; top:0; left:0; height:100%; width:100%; background: url('../img/done.png') no-repeat center center rgba(255,255,255,0.5); display: none; } #dropbox .preview.done .uploaded{ display: block; } #dropbox .progressHolder{ position: absolute; background-color:#252f38; height:12px; width:100%; left:0; bottom: 0; box-shadow:0 0 2px #000; } #dropbox .progress{ background-color:#2586d0; position: absolute; height:100%; left:0; width:0; box-shadow: 0 0 1px rgba(255, 255, 255, 0.4) inset; -moz-transition:0.25s; -webkit-transition:0.25s; -o-transition:0.25s; transition:0.25s; } #dropbox .preview.done .progress{ width:100% !important; }
Bem, com isso temos nossa aplicação web para upload de imagens pronta e funcional. Relembrando, a página de demonstração não faz o upload dos seus arquivos para o meu servidor. E no meu gitbub você pode baixar o código completo para estudá-lo e melhorá-lo.
Diga o que achou. Utilize os comentários. Corrija, sugira, critique. Minha intenção é ajudar à outros desenvolvedores tirando as mesmas dúvidas que já tive uma vez.
Baseado no post HTML5 File Upload with jQuery do Tutorialzine.