Foi escrito e discuto muito sobre se é ou não factível utilizar AJAX para enviar um arquivo ao servidor.Por Damián Suárez
Publicado em: 28/2/08
Por uma necessidade pessoal eu também me vi envolvido nesta série de discussões. A finalidade deste artigo é que seja útil a alguém; principalmente a mim.
Então ...
Ao finalizar este pequeno tutorial você deverá entender perfeitamente este
exemplo.
Primeiro Erro: Título Mal Empregado
Vou me passar como tradutor de inglês...seria algo como Arquivo Subido com AJAX. Isto, hoje, não se pode fazer. É assim e não resta muito a fazer.
Então, você dirá ...
- bom, mas eu em gmail posso subir arquivos e faço com AJAX !!!.
Eu lhe respondo ...
- Não seja bobo, eu também pensava o mesmo.
Há vários indícios que o objeto
XMLHttpRequest não pode enviar arquivos ao servidor.
Então deveríamos mudar o título do post. Seria assim:
Ajax File Upload SEM Ajax
Frente a esta imutável condição os desenvolvedores buscaram uma boa forma de simular scripts para subir arquivos ao servidor como se fosse com AJAX, e pelo menos comigo conseguiram.
- Temos um formulário com um campo tipo file, o qual nos permitirá enviar o arquivo a nosso servidor PHP. A resposta do servidor se fará no IFRAME, ator principal desta novela.
- O script executado em nosso server a causa do action do formulário é o encarregado de copiar o arquivo temporário em um espaço físico dentro do mesmo.
- Logo, com um pouco de ajuda de JS imprimiremos uma mensagem correspondente ao estado final de nosso script.
Primeiro Exemplo - Subir um Arquivo o Server
Utilizaremos somente dois scripts muito simples. Logo iremos melhorando e complementando o desenvolvimento até chegar ao nosso objetivo.
HTML:
<form method="post" enctype="multipart/form-data"
action="controlUpload.php"
target="iframeUpload">
<input type="hidden" name="phpMyAdmin" />
Archivo: <input name="fileUpload" type="file" />
<input type="submit" value="enviar">
<iframe name="iframeUpload"></iframe>
</form>
É um simples formulário HTML com um campo FILE e um marco flutuante iframe denominado iframeUpload. Quando enviamos o arquivo ao servidor executaremos o script controlUpload.php e a resposta do server se fará em nosso iframe já que apontamos ao mesmo dentro da etiqueta target na declaração form.
PHP:
// Script Que copia o arquivo temporário subido ao servidor em um diretorio.
echo '<p>Nome Temporario: '.$_FILES['fileUpload']['tmp_name'].'</p>';
echo '<p>Nome no Server: '.$_FILES['fileUpload']['name'].'</p>';
echo '<p>Tipo de Arquivo: '.$_FILES['fileUpload']['type'];
$tipo = substr($_FILES['fileUpload']['type'], 0, 5);
// Definimos Diretorio onde se salva o arquivo
$dir = 'archs/';
// Tentamos Subir Arquivo
// (1) Comprovamos que existe o nome temporario do arquivo
if (isset($_FILES['fileUpload']['tmp_name'])) {
// (2) - Comprovamos que se trata de um arquivo de imagem
if ($tipo == 'image') {
// (3) Por ultimo se tenta copiar o arquivo ao servidor.
if (!copy($_FILES['fileUpload']['tmp_name'], $dir.$_FILES['fileUpload']['name']))
echo '<script> alert("Erro ao Subir o Arquivo");</script>';
}
else echo 'O Arquivo que se tenta subir NAO E do tipo Imagem.';
}
else echo 'O Arquivo nao chegou ao Servidor.';
Quando se executa o script, este tenta resgatar os dados do arquivo a subir. Para isso se vale do array global de PHP $_FILES. Se não estiver muito familiarizado recomendo que leia esta seção do manual oficial para entender seu funcionamento e suas particularidades.
Nas primeiras linhas apresentamos o nome do arquivo temporário gerado por nosso motor PHP, o segundo é o nome real do arquivo e o terceiro é o tipo de arquivo.
Se estes valores estiverem definidos evidentemente o arquivo chegou ao server. Estas linhas mais adiante não as utilizaremos; agora só as usamos para realizar o seguimento do script.
Atribuímos a $tipo o tipo de arquivo para poder controlar que seja uma imagem. Cortam-se os primeiros 5 caracteres e se tudo for correto $tipo terá o valor image. Se não for uma imagem terá o valor distinto. Este controle se pode fazer de diversas formas; nós utilizamos esta.
Logo, tentamos copiar o arquivo temporário em forma definitiva em algum setor físico em nosso servidor. Verifica-se em forma aninhada definição de nome temporário de arquivo, tipo de arquivo e se o motor concretizou a cópia.
Neste exemplo o faremos na pasta archs/.
Se está tudo bem podemos passar ao segundo passo.
Neste link podemos
provar o script. Podemos
ver os arquivos subidos ao server neste link.
Esclarecimentos:
Há que definir permissões de escritura de PHP no diretório a copiar o arquivo. Em nosso caso é a pasta archs.
Armando o Circo
Comecemos a modificar um pouco os arquivos anteriores.
Em primeiro lugar vamos eliminar o botão submit Enviar e vamos disparar o formulário com uma ordem em JS.
JavaScript:
onchange="javascript: submit()"
Vamos ocultar o iframe.
JavaScript:
style="display:none"
No final do arquivo agregamos uma linha que nos dirige a um simples script que nos mostra os arquivos subidos ao server; mais que nada para que possa corroborar a funcionalidade.
HTML:
<a href="verArquivos.php">Ver Arquivos</a>
Esta linha não se apresenta no script.
HTML:
<form method="post" enctype="multipart/form-data"
action="controlUpload2.php" target="iframeUpload">
Archivo: <input name="fileUpload" type="file" onchange="javascript: submit()" />
<br /><iframe name="iframeUpload" style="display:none"></iframe>
</form>
E ao script controlUpload.php vamos agregar alertas de controle (também com JS por agora). Ademais, vamos eliminar instruções que se tornaram desnecessárias ao ocultar o iframe.
PHP:
// Script Que copia o arquivo temporario subido ao servidor em um diretorio.
$tipo = substr($_FILES['fileUpload']['type'], 0, 5);
// Definimos Diretorio onde se salva o arquivo
$dir = 'archs/';
// Tentamos Subir Arquivo
// (1) Comprovamos que existe o nome temporario do arquivo
if (isset($_FILES['fileUpload']['tmp_name'])) {
// (2) - Comprovamos que se trata de um arquivo de imagem
if ($tipo == 'image') {
// (3) Por ultimo se tenta copiar o arquivo ao servidor.
if (!copy($_FILES['fileUpload']['tmp_name'], $dir.$_FILES['fileUpload']['name']))
echo '<script> alert("Erro ao Subir o Arquivo");</script>';
else
echo '<script> alert("O arquivo '.$_FILES['fileUpload']['name'].' se copiou com Exito");</script>';
}
else echo '<script> alert("O Arquivo que se tenta subir NAO E do tipo Imagem.");</script>';
}
else echo '<script> alert("O Arquivo nao chegou ao Servidor.");</script>';
controlUpload2.php | Ver
Já começa a parecer a um verdadeiro AJAX FILE UPLOAD!
Finalmente um simples Script
Com estas últimas modificações teremos a base final para poder implementar nosso FILE UPLOAD com um comportamento muito similar a gmail.
Vamos conter o formulário em um div com id formUpload.
HTML:
<div id="formUpload">
Ao arquivo upload3.php, à parte do formulário de envio vamos agregá-lhe uma simples função resultadoUpload (estado, file) realizada em JS que, dependendo do código que nos 'envie' controlUpload.php nas variáveis estado e file (agora vemos como ...) imprimirá em tal div uma mensagem de resposta à tentativa de subida.
JavaScript:
function resultadoUpload(estado, file) {
var link = '<br /><br /><a href="upload3.php">Subir Arquivo</a> - <a href="verArquivos.php">Ver Imagens</a>';
if (estado == 0)
var mensagem = 'O Arquivo <a href="archs/' + file + '" target="_blank">' + file + '</a> foi subido ao servidor corretamente' + link;
if (estado == 1)
var mensagem = 'Erro ! - O arquivo nao chegou ao servidor' + link;
if (estado == 2)
var mensagem = 'Erro ! - So se permitem Arquivos tipo Imagem' + link;
if (estado == 3)
var mensagem = 'Erro ! - Nao se pode copiar Arquivo. Possivel problema de permissoes em server' + link;
document.getElementById('formUpload').innerHTML=mensagem;
}
A impressão de nossa mensagem no div se faz na última linha da função.
JavaScript:
document.getElementById('formUpload').innerHTML=mensagem;
Este site tem uma boa descrição do conjunto de funções
getElementBy*. De qualquer forma, com um pouco de sua grande astúcia, você poderá encontrar muitos exemplos de seu funcionamento.
Agora só resta modificar controlUpload.php para que em vez de executar uma janela alert () (como no exemplo anterior) simplesmente execute o código JavaScript para chamar à função resultadoFile () enviando os dados correspondentes à tentativa de subida do arquivo.
O ponto chamativo é como acessamos desde o iframe oculto à função que se encontra na página que o contém. Utilizamos a palavra reservada de JS parent.
JavaScript:
<script>parent.resultadoUpload(estado, file);</script>
As outras modificações são para melhorar esteticamente as páginas. Também se utilizam dois scrips em php. verArquivos.php para ver os arquivos subidos e eliminar.php que não requer muita explicação.
Finalizando
Este humilde tutorial ficou mais longo do que gostaria. Vou continuar trabalhando para melhorar o funcionamento e evoluir. Fica pendente uma barra de progresso (aí creio que não podemos escapar de AJAX) e outras formas de aplicação.
Tomem todo o código como um guia para desenvolver esta pequena aplicação. Faltam muitos controles de erros, de segurança, etc. O código fonte apresentado não é idêntico aos arquivos que se podem baixar; isto é simplesmente por uma questão de prolixidade.
Desculpem minha desordem semântica e gramatical; como a maioria, sou atrevido por jogar o papel de tutor. Nada mais longe de meus fins. Simplesmente o que quero é ajudar assim como me foi ajudado.
Comentários do artigo
Excelente tutorial. Bem escrito, simples e direto. Parabéns!
| Por: Tiago Schreiber | | 18/5/07
|
Muito bom mesmo ta de parabens =D
O melhor artigo sobre o assunto.
Altíssima qualidade.
Vlw amigão, salvou minha pele . . . precisa fazer um desse pra essa semana e não tinha nem idéia do que fazer.
Muito obrigado
 | Loadbar! Por: samuel-prates
| 10/11/08 |
Só falta msm a loadbar...
Funciona 'perfect'!!!
 | Uploadbar! Por: samuel-prates
| 10/11/08 |
Minha pequena modificação, p/ usar uma loadbar.
No msm arquivo do form
<script>
function enviaarq(){
document.getElementById('formUpload').innerHTML = "<img src='LOADBAR.gif' />";
document.arquivos.submit();
}
</script>
No lugar de
<input type="file" name="fileUpload" id="arquivo" onchange="submit()"/>
<input type="file" name="fileUpload" id="arquivo" onchange="enviaarq()" />
E na resposta controlUpload.php
echo '<script>parent.document.getElementById("formUpload").innerHTML = "";</script>';
Pronto! Sua uploadbar funcionando!!!:)
 | Não estou conseguindo baixar os arquivos? Por: claytonpereira
| 24/2/09 |
Acho que os links para os arquivos não estão funcionado. Poderia atualizá-los para mim?