Upload dinâmico com PHP/jQuery

A solução é simples e conhecida: fazer um iframe contendo um campo do tipo file, fazemos o envio desse arquivo dentro do iframe e então com a ajuda do jQuery recuperamos as informações desse arquivo e trazemos para a página pai. Nesse artigo irei utilizar anexo de arquivos como exemplo.

1. Upload (upload.php)

Inicialmente iremos fazer uma página que fará o upload de um arquivo, assim como é feito normalmente.

[PHP]
<?php
// Flag que indica se há erro ou não
$erro = null;
// Quando enviado o formulário
if (isset($_FILES[‘arquivo’]))
{
// Extensões permitidas
$extensoes = array(“.doc”, “.txt”, “.pdf”, “.docx”, “.jpg”);
// Caminho onde ficarão os arquivos
$caminho = “uploads/”;
// Recuperando informações do arquivo
$nome = $_FILES[‘arquivo’][‘name’];
$temp = $_FILES[‘arquivo’][‘tmp_name’];
// Verifica se a extensão é permitida
if (!in_array(strtolower(strrchr($nome, “.”)), $extensoes)) {
$erro = ‘Extensão inválida’;
}
// Se não houver erro
if (!isset($erro)) {
// Gerando um nome aleatório para o arquivo
$nomeAleatorio = md5(uniqid(time())) . strrchr($nome, “.”);
// Movendo arquivo para servidor
if (!move_uploaded_file($temp, $caminho . $nomeAleatorio))
$erro = ‘Não foi possível anexar o arquivo’;
}
}
?>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” xml:lang=”en” lang=”en”>

<head>
<meta http-equiv=”content-type” content=”text/html; charset=utf-8″ />
<title>Upload dinâmico com jQuery/PHP</title>

<script type=”text/javascript” src=”js/jquery.js”></script>
</head>

<body>

<form id=”upload” action=”upload.php” method=”post” enctype=”multipart/form-data”>
<label>Arquivo: </label> <span id=”status” style=”display: none;”><img src=”image/loader.gif” alt=”Enviando…” /></span> <br />
<input type=”file” name=”arquivo” id=”arquivo” />
</form>

</body>
</html>
[/PHP]

Bom pessoal, nesse arquivo será feito apenas um upload simples. Resumindo, quando enviado o formulário nós recuperamos as informações desse arquivo, verificamos se sua extensão é válida, caso seja, geramos um nome aleatório para esse arquivo e enviamos para o servidor.

Vamos agora criar nosso código javascript (utilizando jQuery), que será incluído no cabeçalho desse arquivo:

[PHP] $(function($) {
// Definindo página pai
var pai = window.parent.document;

<?php if (isset($erro)): // Se houver algum erro ?>

// Exibimos o erro
alert(‘<?php echo $erro ?>’);

<?php elseif (isset($nome)): // Se não houver erro e o arquivo foi enviado ?>

// Adicionamos um item na lista (ul) que tem ID igual a “anexos”
$(‘ul#anexos’, pai).append(‘<li lang=”<?php echo $nomeAleatorio ?>”><?php echo $nome ?> <img src=”image/remove.png” alt=”Remover” onclick=”removeAnexo(this)” \/> </li>’);

<?php endif ?>

// Quando selecionado um arquivo
$(“#arquivo”).change(function() {
// Se o arquivo foi selecionado
if (this.value != “”)
{
// Exibimos o loder
$(“#status”).show();
// Enviamos o formulário
$(“#upload”).submit();
}
});
});[/PHP]

Talvez não faça tanto sentido agora, porém mais adiante você entenderá melhor, vamos aos detalhes:

  • Linha 3: Como esse arquivo ficará dentro de um iframe, precisamos saber quem é a página pai, para isso definimos uma variável com o documento da página pai;
  • Linha 5, 8: Aqui está um detalhe interessante. Como a linguagem servidor (PHP) é executada primeiro que a cliente (javascript), nós fazemos um teste. Se a variável erro foi definida, nós imprimimos um alert, que depois será executada pelo javascript, que exibirá uma mensagem de alerta com o erro que foi armazenado;
  • Linha 10: Caso não haja erro, e a variável nome foi definida, ou seja, o arquivo foi enviado;
  • Linha 13: Colocamos na lista (que será criada adiante) com ID igual a anexos um item, porém perceba que foi passado no segundo parâmetro do seletor a variável pai, portanto ele irá buscar o ul#anexos da página pai. Nesse item colocamos o nome aleatório do arquivo na propriedade LANG. Logo após, colocamos uma imagem que será responsável por remover o anexo, note que definimos, no evento onclick, a chamada da função removeAnexo(), está será explicada adiante.
  • Linha 18: Quando o usuário selecionar um arquivo.
  • Linha 20: Verificamos se um arquivo foi realmente selecionado.
  • Linha 23: Exibimos nosso loader (carregando).
  • Linha 25: Enviamos o formulário via javascript.

2. A página pai (index.php)

Está será a página principal, onde colocaremos o iframe que incluirá o nosso arquivo de upload:

[PHP]<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” xml:lang=”en” lang=”en”>

<head>
<meta http-equiv=”content-type” content=”text/html; charset=utf-8″ />
<title>Upload dinâmico com jQuery/PHP</title>

<script type=”text/javascript” src=”js/jquery.js”></script>

</head>

<body>

<h1>Upload dinâmico com jQuery/PHP</h1>

<ul id=”anexos”></ul>
<iframe src=”upload.php” frameborder=”0″ scrolling=”no”></iframe>

<form id=”upload” action=”index.php” method=”post”>
<input type=”submit” name=”enviar” value=”Enviar” />
</form>

</body>
</html>[/PHP]

Nessa estrutura, criamos a lista (ul#anexos) onde serão adicionados os anexos, logo abaixo criamos nosso iframe e chamamos nosso arquivo de upload (upload.php). A essa altura, nosso upload dinâmico já está “funcional”, porém precisamos criar a função para remover o anexo:

[JAVASCRIPT]// Função para remover um anexo
function removeAnexo(obj)
{
// Recuperando nome do arquivo
var arquivo = $(obj).parent(‘li’).attr(‘lang’);
// Removendo arquivo do servidor
$.post(“index.php”, {acao: ‘removeAnexo’, arquivo: arquivo}, function() {
// Removendo elemento da página
$(obj).parent(‘li’).remove();
});
}[/JAVASCRIPT]
  • Linha 2: Criamos nossa função que receberá como parâmetro o elemento da imagem;
  • Linha 5: A imagem está dentro do item (li), certo? Portanto, através do método parent() selecionamos o item (li) e pegamos o valor da propriedade LANG (Lembra que colocamos o nome do arquivo aqui?);
  • Linha 7: Fazemos uma requisição ajax com nosso próprio arquivo, e passamos como ação ‘removeAnexo’ e também o nome do arquivo anexado. Isso será preciso para que possamos remover o arquivo do servidor;
  • Linha 9: Quando terminado a requisição, removemos o elemento li de nossa página.

Vamos então criar a função PHP (logo no inicio do arquivo) que removerá o arquivo do servidor:

[PHP]<?php
// Quando a ação for para remover anexo
if ($_POST[‘acao’] == ‘removeAnexo’)
{
// Recuperando nome do arquivo
$arquivo = $_POST[‘arquivo’];
// Caminho dos uploads
$caminho = ‘uploads/’;
// Verificando se o arquivo realmente existe
if (file_exists($caminho . $arquivo) and !empty($arquivo))
// Removendo arquivo
unlink($caminho . $arquivo);
// Finaliza a requisição
exit;
}
?>[/PHP]

Parece que agora acabou né? Ainda não. Como iremos recuperar esses anexos quando enviado o formulário? Já que nosso formulário está simplesmente assim:

[PHP]<form id=”upload” action=”index.php” method=”post”>
<input type=”submit” name=”enviar” value=”Enviar” />
</form>[/PHP]

A solução é criar campos ocultos com os nomes dos arquivos quando enviado o formulário, para isso:

[JAVASCRIPT]$(function($) {
// Quando enviado o formulário
$(“#upload”).submit(function() {
// Passando por cada anexo
$(“#anexos”).find(“li”).each(function() {
// Recuperando nome do arquivo
var arquivo = $(this).attr(‘lang’);
// Criando campo oculto com o nome do arquivo
$(“#upload”).prepend(‘<input type=”hidden” name=”anexos[]” value=”‘ + arquivo + ‘” \/>’);
});
});
});[/JAVASCRIPT]
  • Linha 3: Quando nosso formulário for enviado;
  • Linha 5: Procuramos cada item (li) em nossa lista de anexo e passamos por cada um através do laço each();
  • Linha 7: Recuperamos o nome (aleatório) do arquivo que foi armazenado na propriedade LANG;
  • Linha 9: Através do prepend() adicionamos um campo oculto (hidden) dentro de nosso formulário (#upload) e colocamos o nome do arquivo como valor. Note que atribuímos o nome como anexos[] para que assim possamos recuperar os anexos já dentro de um array com PHP.

Agora, para fins de teste você pode adicionar o seguinte no inicio do arquivo:

[PHP]// Se enviado o formulário
if (isset($_POST[‘enviar’]))
{
echo ‘Arquivos enviados: ‘;
echo ‘<pre>’;
// Exibimos os arquivos anexados
print_r($_POST[‘anexos’]);
echo ‘</pre>’;
}[/PHP]

Assim, você pode perceber, que quando enviado o formulário, o nome de nossos arquivos ficaram no array anexos e então podemos armazená-los no banco de dados, por exemplo.

3. Finalizando

Bom pessoal, meu objetivo nesse artigo foi apresentar uma alternativa para “simular” um upload com ajax. Se você tiver outra alternativa, compartilhe conosco. Dúvidas ou críticas construtivas são sempre bem vindas.

Espero que vocês tenham entendido, até a próxima.
Abraços.

Envio de formulario sem refresh com JQuery/PHP

Olá pessoal, tudo bom? Hoje, nesse artigo que foi sugerido, irei abordar mais uma opção de fazer uma requisição AJAX, agora com JQuery.
Como exemplo vou utilizar uma página onde o usuário pode deixar sua mensagem sem precisar dar refresh na página. Os arquivos estão disponíveis para download no final do arquivo. Vamos lá.

Veja o código em funcionamento

1. Banco de dados

Primeiramente, como sempre, vamos criar nossa base de dados e inserir alguns registros de exemplo:

[sql]

CREATE TABLE IF NOT EXISTS mensagens (
id int(11) NOT NULL AUTO_INCREMENT,
nome varchar(50) NOT NULL,
email varchar(50) NOT NULL,
mensagem text NOT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;

INSERT INTO mensagens (id, nome, email, mensagem) VALUES
(1, ‘faael’, ‘faelcalves@hotmail.com’, ‘Hello world!’),
(2, ‘Fulano’, ‘fulano@dominio.com’, ‘Olá Mundo!’);

[/sql]

2. Conexão (conn.php)

Vamos criar também o arquivo responsável pela conexão com nosso banco de dados:

[php]
<?php
// Informações para conexão
$host = "localhost";
$usuario = "root";
$senha = "senha";
$banco = "banco";
// Realizando conexão e selecioando banco de dados
$conn = mysql_connect($host, $usuario, $senha) or die(mysql_error());
$db = mysql_select_db($banco, $conn) or die(mysql_error());
// Alterando o charset para utf8, para evitar problemas de acentuação
mysql_set_charset(‘utf8’);
?>
[/php]

Edite as informações de acordo com as configurações de seu banco de dados

3. A página (index.php)

Criaremos a base da nossa página, com algumas divs e o formulário:

[php]
<?php require_once("conn.php"); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Envio de formulário sem refresh com JQuery/PHP</title>
</head>

<body>
<h1>Escrever Mensagem</h1>

<div id="status" style="display: none;"></div>

<div id="escrever">
<form id="formulario" action="javascript:func()" method="post">
<strong>Nome:</strong> <br />
<input name="nome" type="text" id="nome" size="35" /> <br /><br />

<strong>Email:</strong> <br />
<input name="email" type="text" id="email" size="35" /> <br /><br />

<strong>Mensagem:</strong> <br />
<input name="mensagem" type="text" id="mensagem" size="145" /><br /><br />

<input type="submit" value="Enviar" />

</form>
</div>

<h1>Mensagens</h1>

<div id="mensagens"></div>

</body>
</html>
[/php]

Bom, agora vamos começar a trabalhar. Primeiramente, iremos baixar a biblioteca do jquery, clique aqui para baixar. Depois de baixado, vamos incluí-lo na nossa página, entre as tags <head></head>:

Inserido o jquery, vamos colocar as mensagens do banco de dados na div mensagens:

[php]
<div id="mensagens">
<?php
// Buscamos e exibimos as mensagens já contidas no banco de dados
$query = mysql_query("SELECT * FROM mensagens ORDER BY id DESC");
while($mensagem = mysql_fetch_object($query)) {
echo "<strong>" . $mensagem->nome . "</strong> disse: <em>" . $mensagem->mensagem . "</em><br />";
}
?>
</div>
[/php]

Retornando no jquery, vamos agora criar a função que fará a requisição ajax, essa deverá estar entre as tags <head></head> também:

[js]
<script type="text/javascript" language="javascript">
$(function($) {
// Quando o formulário for enviado, essa função é chamada
$("#formulario").submit(function() {
// Colocamos os valores de cada campo em uma váriavel para facilitar a manipulação
var nome = $("#nome").val();
var email = $("#email").val();
var mensagem = $("#mensagem").val();
// Exibe mensagem de carregamento
$("#status").html("<img src=’loader.gif’ alt=’Enviando’ />");
// Fazemos a requisão ajax com o arquivo envia.php e enviamos os valores de cada campo através do método POST
$.post(‘envia.php’, {nome: nome, email: email, mensagem: mensagem }, function(resposta) {
// Quando terminada a requisição
// Exibe a div status
$("#status").slideDown();
// Se a resposta é um erro
if (resposta != false) {
// Exibe o erro na div
$("#status").html(resposta);
}
// Se resposta for false, ou seja, não ocorreu nenhum erro
else {
// Exibe mensagem de sucesso
$("#status").html("Mensagem enviada com sucesso!");
// Coloca a mensagem no div de mensagens
$("#mensagens").prepend("<strong>"+ nome +"</strong> disse: <em>" + mensagem + "</em><br />");
// Limpando todos os campos
$("#nome").val("");
$("#email").val("");
$("#mensagem").val("");
}
});
});
});
</script>
[/js]

É nessa função que praticamente tudo acontece. Vou tentar detalhar mais ela:

Linha 4: Chamamos a função quando o formulário é enviado, ou seja, no evento submit.

Linha 6,7,8: Colocamos os valores de cada campo do formulário em uma variável correspondente, para que assim facilite a manipulação desses valores.

Linha 10: Colocamos na div status a imagem de “carregando”. Você pode criar seus próprios “loaders” noajaxload.info.

Linha 12: É aqui que chamamos o arquivo envia.php que fará a validação dos dados e, se corretos, a adição dos mesmos no banco de dados. No primeiro parâmetro, passamos o arquivo, no caso o envia.php; No segundo passamos os valores que serão passados pelo método POST; No terceiro chamamos a função que tratará da resposta no final da requisição.

Linha 15: Exibimos a div status com o efeito slideDown(); Lembrando que o display da div deve ser none, senão não haverá efeito.

Linha 17: Verificamos se a resposta é diferente de false, ou seja, se houve algum erro.

Linha 19: Se houver erro, a mensagem de erro é colocado na div status.

Linha 22: Se não houver nenhum erro na validação.

Linha 25: Colocamos na div status uma mensagem de sucesso.

Linha 27: Colocamos na div mensagens a nova mensagem que foi enviada. A propriedade prepend adiciona um conteúdo antes do conteúdo original da div.

Linha 29,30,31: Limpamos os campos do formulário.

4. PHP (envia.php)

Só restou criar o envia.php, que fará toda a validação dos dados e irá adicioná-los no banco de dados, pra quem conhece php, creio que não terá nenhuma novidade:

[php]
<?php
// Incluimos o arquivo de conexão
require_once("conn.php");
// Recuperamos os valores dos campos através do método POST
$nome = $_POST["nome"];
$email = $_POST["email"];
$mensagem = $_POST["mensagem"];
// Verifica se o nome foi preenchido
if (empty($nome)) {
echo "Escreva seu nome";
}
// Verifica se o email é válido
elseif (!eregi("^[a-z0-9_.-]+@[a-z0-9_.-]*[a-z0-9_-]+.[a-z]{2,4}$", $email)) {
echo "Digite um email válido";
}
// Verifica se a mensagem foi digitada
elseif (empty($mensagem)) {
echo "Escreva uma mensagem";
}
// Verifica se a mensagem nao ultrapassa o limite de caracteres
elseif (strlen($mensagem) > 140) {
echo "A mensagem deve ter no máximo 140 caracteres";
}
// Se não houver nenhum erro
else {
// Inserimos no banco de dados
$query = mysql_query("INSERT INTO mensagens VALUES (”, ‘".$nome."’, ‘".$email."’, ‘".$mensagem."’)");
// Se inserido com sucesso
if ($query) {
echo false;
}
// Se houver algum erro ao inserir
else {
echo "Não foi possível inserir a mensagem no momento.";
}
}
?>
[/php]

Aqui simplesmente verificamos se os dados são válidos e retornamos apenas uma resposta, ou seja, uma mensagem de erro ou um “false” (Esse valor define que tudo está correto);

5. Conclusão

Bom pessoal, é isso; tentei explicar da melhor forma possível de forma rápida. Espero que vocês tenham entendido, qualquer dúvida só entrar em contato, ok?

Download dos arquivos

Abraços.