Upload de imagens com HTML5, jQuery e PHP

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:

  1. 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;
  2. 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;
  3. 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.

Leave a Reply