Desenvolvimento - PHP

PHP - Classe para Upload de Arquivo

Nesse artigo veremos como criar uma classe para upload de imagem no PHP, fica fácil assim implementar um objeto de Upload em qualquer página.

por André Baltieri



Começando este artigo trataremos do uso de classes no PHP.
Vendo a necessidade de enviar arquivos, resolvi criar uma classe para isso.
Uma das principais funções de uma classe é a reutilização de código, ou seja, escrever menos e fazer mais.
Vamos à classe então.

Por medidas de segurança, antes de fazermos qualquer coisa, faremos uma verificação para ver se a página que contém a classe está sendo chamada direta pela URL. Por exemplo, se eu tento acessar o arquivo dessa forma:
http://www.meusite.com.br/minhaClasse.php
Essa verificação irá me retornar ao index (Página principal), pois não é seguro um usuário conseguir acessar nossas classes.

Para tal verificação, usamos os seguintes comandos:

1. //Verificação de Segurança
2. $url = $_SERVER["PHP_SELF"];
3. if(eregi("class.Upload.php", "$url"))
4. {
5. header("Location: ../index.php");
6. }

Linha 2 - A variável $url recebe o valor da URL atual.
Linha 3 - Usamos a função eregi para NÃO fazer diferença entre minúsculas e maiúsculas em nossa comparação. Em seguida, é verificado se a a URL digitada tem o mesmo nome do nosso arquivo. Caso tenha, vai para a linha 5.
Linha 5 - Usamos o header para enviar o usuário de volta para o index.

Após feita a verificação, já podemos começar a criação da nossa classe.
Para isso, usamos o comando:

1. class Upload
2. {
3.
4. }

Para esta classe, vi a necessidade de usarmos 3 atributos, sendo eles: tipo, nome e tamanho.
Criamos então estes atributos.

1. class Upload
2. {
3. var $tipo;
4. var $nome;
5. var $tamanho;
6. }

Agora que temos os atriutos criados, podemos recuperar os dados do arquivo enviado.
No PHP as variáveis não necessitam de tipagem, então é só declará-las.

O próximo passo em nossa classe é criar as funções.
Nossa primeira função será a função upload, que apenas será utilizada para instanciarmos o objeto na nossa página posteriormente.

1. function Upload()
2. {
3. //Só cria o objeto
4. }

Simples.

Agora já podemos instânciar nosso objeto, usando o comando $arquivo = new Upload;
Porém, não temos nenhuma ação ainda.
Então, vamos criar nossa função principal.

Para esta função, serão necessários 3 atributos também, sendo eles:
$arquivo - Arquivo que o nosso form nos enviou.
$pasta - Pasta onde será salvo nosso arquivo (Lembre-se de aplicar permissões de escrita na pasta em que o arquivo será salvo).
$tipo - O tipo na verdade, será uma lista (Array), contendo todos os tipos de arquivo permitidos.

Outro problema encontrado, é que na hora que um arquivo é enviado ao servidor, se já houver outro arquivo com o mesmo nome, ele será substituido.
Além disso, em servidores Linux, há uma certa confusão com caracteres, e muitos usuários não sabem sobre isso, ou não querem ficar renomeando o arquivo para enviá-lo.
O que iremos fazer então é criar um hash (Um código), usando a encriptação MD5.
Esse hash será gerado da junção do nome do arquivo com a data atual.
No final, poderemos reparar, que o nome do arquivo enviado ficará apenas um código extenso.

Exemplo:
Arquivo Enviado: imagem_teste.jpg
Nome do arquivo depois de enviado ao servidor: 33ea8043909c3726e2eacbf4a82e5227.jpg

Com isso, evitamos erros a partir de caracteres especiais e nome de arquivos extensos e também evitamos a substituição de arquivos em nosso servidor.

Então vamos criar a função

1. function UploadImagem($arquivo, $pasta, $tipos)
2. {
3.
4. }

Até aí tudo certo.

Vamos agora às verificações:
A primeira coisa que iremos fazer, é verificar se algum arquivo foi enviado, pois sem arquivo, não conseguimos fazer nada.

1. function UploadArquivo($arquivo, $pasta, $tipos)
2. {
3. if(isset($arquivo))
4. {
5.
6. }
7. }

Na linha 3, verificamos com o isset, se o arquivo foi enviado.
Se não foi, nada irá acontecer.
Caso o arquivo tenha sido postado, iremos recuperar alguns atributos dele.

1. function UploadImagem($arquivo, $pasta, $tipos)
2. {
3. if(isset($arquivo))
4. {
5. $nomeOriginal = $arquivo["name"];
6. $nomeFinal = md5($nomeOriginal . date("dmYHis"));
7. $tipo = strrchr($arquivo["name"],".");
8. $tamanho = $arquivo["size"];
9. }
10. }

Primeiramente, devemos saber que o arquivo vem em forma de array, contendo assim vários atributos.
Na linha 5, criamos a variável $nomeOriginal, que recebe em seguida o nome do arquivo, que é recuperado pela sintaxe $arquivo["name"].
Na linha 6, criamos uma variável chamada $nomeFinal, que receberá o nome final do arquivo.

Lembre-se que acima falamos de um problema de sobrescrever arquivos e de caracteres especiais no nome do arquivo.
Para corrigir isso, ainda na linha 6, utilizo o MD5 para gerar uma hash. md5($nomeOriginal . date("dmYHis"));
Nesta sintaxe, eu concateno o nome original do arquivo enviado com a data e hora atual, ficando mais ou menos assim:
Exemplo: imagem_teste.jpg06012008102755
Depois gero uma hash de todo esse nome.
Na linha 7, crio uma variável chamada $tipo e utilizo o strrchr para pegar o último indíce depois do ".", no nome do arquivo. Sendo assim posso obter o tipo do arquivo.
Na linha 8, crio uma variável de nome $tamanho atribuo a ela, o tamanho do meu arquivo.

Com os dados recuperados, temos que fazer agora uma verificação, para saber se o tipo do arquivos que estamos tentando enviar é permitido.
Os tipos de arquivos permitidos são passados através da variável $tipos que é um array.
Iremos então fazer um laço para varrer este array e comparar item por item para ver se a extensão do arquivo enviado é válido.

1. function UploadImagem($arquivo, $pasta, $tipos)
2. {
3. if(isset($arquivo))
4. {
5. $nomeOriginal = $arquivo["name"];
6. $nomeFinal = md5($nomeOriginal . date("dmYHis"));
7. $tipo = strrchr($arquivo["name"],".");
8. $tamanho = $arquivo["size"];
9.
10. for($i=0;$i<=count($tipos);$i++)
11. {
12. if($tipos[$i] == $tipo)
13. {
14. $arquivoPermitido=true;
15. }
16. }
17.
18. }
19. }

Na linha 10, inicio meu for, com a variável $i começando de zero (Array no PHP começa do 0), até que minha variável $i seja menor ou igual ao total de itens do meu array $tipos. O total de itens de um array pode ser obtido através da sintaxe count($array);
Por fim, incremento minha variável com 1, o famoso $i++
Na linha 12, verifico se o tipo atual do laço($tipos[$i]) é igual ao valor de $tipo que tem como valor a extensão do arquivo recuperado.
Caso sim, vamos para a linha 14.
Na linha 14, crio uma nova variável chamada $arquivoPermitido. Essa variável é do tipo boolean e recebe true se o arquivo for permitido ou false se o arquivo não for permitido.
Caso nosso arquivo não seja permitido, exibiremos uma mensagem e sairemos da função.

1. function UploadImagem($arquivo, $pasta, $tipos)
2. {
3. if(isset($arquivo))
4. {
5. $nomeOriginal = $arquivo["name"];
6. $nomeFinal = md5($nomeOriginal . date("dmYHis"));
7. $tipo = strrchr($arquivo["name"],".");
8. $tamanho = $arquivo["size"];
9.
10. for($i=0;$i<=count($tipos);$i++)
11. {
12. if($tipos[$i] == $tipo)
13. {
14. $arquivoPermitido=true;
15. }
16. }
17.if($arquivoPermitido==false)
18.{
19. echo "Extensão de arquivo não permitido!!";
20. exit;
21.}
22.
23. }
24. }

Na linha 17, verificamos se o $arquivoPermitido é false, ou seja o arquivo não é permitido.
Caso seja false, escrevemos a mensagem "Extensão de arquivo não permitida!!" e com o exit; saimos da função.

Bem, agora com as verificações feitas, vamos finalmente subir o arquivo.
Todo arquivo quando carregado, fica na pasta temporária do seu sistema operacional, sendo assim, temos que recuperar esse valor ao enviá-lo.

1. if (move_uploaded_file($arquivo["tmp_name"], $pasta . $nomeFinal . $tipo))
2. {
3. $this->nome=$pasta . $nomeFinal . $tipo;
4. $this->tipo=$tipo;
5. $this->tamanho=number_format($arquivo["size"]/1024, 2) . "KB";
6. return true;
7. }else{
8. return false;
9. }

Na linha 1, movemos o arquivo com a sintaxe move_uploaded_file(arquivo, destino);
Para a mesma, passamos os seguintes valores:
$arquivo["tmp_name"] que é o nome temporário do arquivo que carregamos.
$pasta que recebeu o valor da função uploadArquivo($arquivo, $pasta, $tipos).
$nomeFinal que foi a hash que geramos com o MD5.
$tipo que é o tipo do arquivo que carregamos.
Quando colocamos o if(move_uploaded_file) estamos fazendo uma verificação.
Se caso o arquivo não possa ser movido, retornamos false.
Caso possa ser movido, executamos as linhas 3, 4, 5 e 6.
Na linha 3, eu atribuo o caminho e nome do arquivo final para o atributo $nome, que criamos no topo da função. Para atribuir valores a atributos internos, precisamos usar o $this->atributo.
Com o valor atribuido, poderemos recuperar esse valor mais tarde, em nossas páginas.
O mesmo é feito com o $tipo e com o $tamanho.
Para finalizar, retornamos true, indicando que nossa operação foi realizada com sucesso.

Ao final de tudo, nossa classe deve estar assim:
Nome do arquivo: class.Upload.php

1. <?php
2. /*
3. Por: André Luis Alves Baltieri
4. Descrição: Classe para upload de arquivo
5. Ultima Alteração: 17/10/2007
6. */
7. ?>
8. <?php
9. //Verificação de Segurança
10. $kurl = $_SERVER["PHP_SELF"];
11. if(eregi("class.Upload.php", "$url"))
12. {
13. header("Location: ../index.php");
14. }


15.
16. class Upload
17. {
18. var $tipo;
19. var $nome;
20. var $tamanho;
21.
22. function Upload()
23. {
24. //Só cria o objeto
25. }
26.
27. function UploadArquivo($arquivo, $pasta, $tipos)
28. {
29. if(isset($arquivo))
30. {
31. $nomeOriginal = $arquivo["name"];
32. $nomeFinal = md5($nomeOriginal . date("dmYHis"));
33. $tipo = strrchr($arquivo["name"],".");
34. $tamanho = $arquivo["size"];
35.
36. for($i=0;$i<=count($tipos);$i++)
37. {
38. if($tipos[$i] == $tipo)
39. {
40. $arquivoPermitido=true;
40. }
42. }
43.
44. if($arquivoPermitido==false)
45. {
46. echo "Extensão de arquivo não permitido!!";
47. exit;
48. }
49.
50. if (move_uploaded_file($arquivo["tmp_name"], $pasta . $nomeFinal . $tipo))
51. {
52. $this->nome=$pasta . $nomeFinal . $tipo;
53. $this->tipo=$tipo;
54. $this->tamanho=number_format($arquivo["size"]/1024, 2) . "KB";
55. return true;
56. }else{
57. return false;
58. }
59. }
60. }
61. }
62. ?>

Com a nossa classe criada, agora é só instanciar o objeto em nossa página e fazer a chamada.
Vamos agora criar a nossa página de envio de arquivos.
Nome do arquivo: formArquivo.html

1. <form action="envia_arquivos.php" method="post" enctype="multipart/form-data">
2. <input type="hidden" name="MAX_FILE_SIZE" value="300000">
3. <input name="userfile" type="file">
4. <input type="submit" value="Enviar Arquivo">
5. </form>

Vemos que na linha 1, na tag form, temos que definir o enctype como multipart/form-data, para que possamos enviar arquivos.
Na linha 2, adicionamos um campo hidden(Escondido) com o nome de MAX_FILE_SIZE e valor de 300000, isso define que o Tamanho máximo permitido para um arquivo ser enviado é de 300000 bytes.
Na linha 3, inserimos um input do tipo file(arquivo), ele será responsável por carregar nosso arquivo.
Por ultimo, na linha 4, adicionamos o botão para enviar nosso formulario.

Com o nosso formulário criado, vamos então fazer o upload do arquivo.
Criamos então uma nova página com o nome de envia_arquivos.php.
Nome do Arquivo: envia_arquivos.php

1. <?php
2. include("class.Upload.php");
3.
4. //define os tipos permitidos
5. $tipos[0]=".gif";
6. $tipos[1]=".jpg";
7. $tipos[2]=".jpeg";
8. $tipos[3]=".png";
9.
10. if(isset($HTTP_POST_FILES["userfile"]))
11. {
12. $upArquivo = new Upload;
13. if($upArquivo->UploadArquivo($HTTP_POST_FILES["userfile"], "Imagens/", $tipos))
14. {
15. $nome = $upArquivo->nome;
16. $tipo = $upArquivo->tipo;
17. $tamanho = $upArquivo->tamanho;
18. }else{
19. echo "Falha no envio<br />";
20. }
21. }
22. ?>
23. <strong>Nome do Arquivo Enviado:</strong> <?php echo $nome ?><br />
24. <strong>Tipo do Arquivo Enviado:</strong> <?php echo $tipo ?><br />
25. <strong>Tamanho do Arquivo Enviado:</strong> <?php echo $tamanho ?><br />

Na linha 2, fazemos a inclusão da nossa classe.
Nas linhas 4, 5, 6, 7 e 8, definimos os tipos de arquivos permitidos.
Na linha 10, verificamos se veio algum arquivo do formulário.
Na linha 12, instanciamos nossa classe criando o objeto $upArquivo.
na linha 13, chamamos a função UploadArquivo e passamos para ela o arquivo($HTTP_POST_FILES["userfiles"]), a pasta onde os arquivos carregados serão enviados ("Imagens/") e os tipos de arquivos permitidos ($tipos).
Com o if antes de tudo, fazemos uma verficação. Lembre-se da classe que criamos, onde retornavamos true se tudo ocorresse certo.
Então nas linhas 15, 16, 17, atribuimos os valores do arquivo a nossas novas variáveis. Por isso, na classe, definimos aquela 3 variáveis no começo da classe, para podermos estar recebendo os valores atribuidos a elas agora.
Por fim, nas linhas 23, 24 e 25, exibimos na tela os valores recebidos.

Ufa.. dá um pouco de trabalho, mas economiza muitas linhas de código.
Esse é meu ponto de vista da criação de classes. Essas foram as maneiras que encontrei de fazer um upload simples e eficaz, é claro que existem várias outras maneiras de fazer, ai fica a critério de cada um.
André Baltieri

André Baltieri - Trabalha com desenvolvimento de aplicações web a mais de 7 anos, e com ASP.NET desde 2003. É líder da comunidade Inside .NET (http://www.insidedotnet.com.br/) e do projeto Learn MVC .NET (http://learn-mvc.net/). Bacharelando em Sistemas de Informação, atualmente trabalha com desenvolvimento e suporte de aplicações web em ASP.NET/C# em projetos internacionais e ministra treinamentos e consultorias sobre a plataforma .NET.