Upload de arquivos com PHP
janeiro 1st, 2009 | by DragaO~ |Neste tópico ensinarei um modo prático de fazer upload de arquivos apenas utilizando PHP sem a necessidade de um banco de dados :D
bom, antes de mais nada, precisamos de um formulário para enviar nossos arquivos né ? ;)
vamos salvar o arquivo abaixo como “formulario.php” :
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!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=iso-8859-1" /> <title>Formulário de Upload de Arquivo</title> </head> <body> <form action="envia_arquivo.php" method="post" enctype="multipart/form-data"> <input type="file" name="arquivo" /> <input type="submit" value="Fazer Upload" /> </form> </body> </html> |
pronto, algo bastante simples ;)
bom, vamos direto ao que interessa :D
8 | <form action="envia_arquivo.php" method="post" enctype="multipart/form-data"> |
- a tag “form” é utilizada para criar formulários
- a tag “form” recebe diversos parâmetros, entre eles estão :
- action : responsável por especificar qual arquivo/script será o responsável por tratar os dados contidos no formulário; o padrão é o próprio arquivo a ser executado (no caso, “formulario.php”)
- method : pode ser “get” ou “post”, serve para especificar qual o método de envio das variaveis e valores para a página de tratamento de dados; o padrão é “get”
- enctype : especifica o método de encode dos dados, pode ser “application/x-www-form-urlencoded” ou “multipart/form-data”; o padrão é “application/x-www-form-urlencoded”
todos formulários devem possuir, no mínimo, estes três parâmetros (caso você não especifique algum deles, o valor padrão será utilizado)
o mais importante de tudo é que, um formulário de upload de arquivos deve possuir enctype do tipo “multipart/form-data”, pois este tipo de encode é utilizado para o envio de formulários com grandes quantidades de informação, que é o nosso caso ;)
a especificação da W3C contém o seguinte texto (traduzido por mim) :
O conteúdo “multipart/form-data” segue as regras de todos fluxos de dados MIME como descritos em [RFC2045]. A definição de “multipart/form-data” está disponível no registro [IANA].
Uma mensagem “multipart/form-data” contém uma série de partes, cada uma representando um controle de sucesso. As partes são mandadas para o agente de processamento na mesma ordem que aparece no documento de entrada. Não deve ocorrer interrupção em nenhum dos dados; como isto é feito sai do propósito desta especificação.
texto original :
The content “multipart/form-data” follows the rules of all multipart MIME data streams as outlined in [RFC2045]. The definition of “multipart/form-data” is available at the [IANA] registry.
A “multipart/form-data” message contains a series of parts, each representing a successful control. The parts are sent to the processing agent in the same order the corresponding controls appear in the document stream. Part boundaries should not occur in any of the data; how this is done lies outside the scope of this specification.
isso basicamente diz, que ao utilizar-mos dados que não sejam apenas texto puro, devemos utilizar “multipart/form-data” e não “application/x-form-www-urlencoded”
para a explicação completa da W3C sobre formulários, clique aqui (caso tenha interesse apenas nessa parte sobre o “enctype”, clique aqui)
9 | <input type="file" name="arquivo" /> |
nessa linha estamos criando um campo para escolher um arquivo a ser enviado ao servidor, e estamos definindo o nome deste campo para “arquivo”
10 | <input type="submit" value="Fazer Upload" /> |
para enviar o formulário nós precisamos de um botão para ser clicado, e aqui estamos criando justamente ele, o botão :)
o restante é apenas bom e puro HTML, portanto creio que dispense explicações, até mesmo porque, caso você não saiba, aconselho que estude HTML antes de tentar passar pro PHP
agora vamos, finalmente, criar o arquivo “envia_arquivo.php”, que vai ser o responsável pelo tratamento e envio do arquivo ao servidor :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <? //nome da pasta onde vao ficar armazenados os arquivos $pasta = "uploads"; //como estamos apenas enviando um arquivo, basta que a variavel superglobal "$_FILES['arquivo'] //exista para que possamos efetuar o upload if($_FILES['arquivo']['tmp_name']) { //atribuindo o nome do arquivo $nome = $_FILES['arquivo']['name']; //movendo o arquivo para o local especificado if(move_uploaded_file($_FILES['arquivo']['tmp_name'], $pasta."/".$nome)) { echo "Arquivo movido"; } else { echo "Falha ao mover arquivo"; } } ?> |
simples, rápido, prático e indolor ;)
agora, explicando as linhas :
3 | $pasta = "uploads"; |
aqui estamos apenas definindo o nome da pasta onde ficarão os uploads (lembre-se, neste exemplo, a pasta deve existir)
7 | if($_FILES['arquivo']['tmp_name']) |
aqui estamos fazendo um teste simples para verificar a existência de um arquivo vindo pelo formulário
agora devemos parar um pouco para falar sobre o array superglobal “FILES”
o array superglobal “FILES” existe (assim como “GET” e “POST”) em todos scripts PHP, querendo ou não eles estão lá e podem ser acessados à qualquer momento (conter ou não algum valor é outra história)
acontece que o array “FILES” possui algumas dimensões, são elas :
$_FILES['arquivo']['name']
responsável por armazenar o nome original do arquivo enviado (algo como “Minha foto.jpg”)
$_FILES['arquivo']['tmp_name']
responsável por conter o caminho completo para o arquivo no servidor (algo como “/tmp/JECpR5.tmp”)
$_FILES['arquivo']['type']
responsável por conter o tipo MIME do arquivo enviado (algo como “image/jpg”)
$_FILES['arquivo']['size']
responsável por conter o tamanho (em bytes) do arquivo (algo como ” 52728″ para caso a imagem tenha “52 Kb”)
$_FILES['arquivo']['error']
quando occorrer algum erro, esta variável vai conter o código do erro (para a lista completa de códigos, veja isso)
caso nenhum arquivo tenha sido enviado, nao irá cair nesse “if”, pois essa dimensão do array é composta pelo nome do arquivo temporário criado pelo PHP
10 | $nome = $_FILES['arquivo']['name']; |
nesta linha estamos atribuindo a variável que vai conter o nome do arquivo
neste exemplo optei por deixar o nome original do arquivo, pois este exemplo apenas possui fins de aprendizado, não é aconselhado deixar os nomes originais de arquivos, algumas dicas:
- nomes com espaços não são legais, acreditem
- o PHP é case-sensitive (diferencia “m” de “M”), portanto, não é interessante ter um arquivo chamado “MinHaFeXtiNha.JPG”, pois, acreditem, fica deselegante (e também deixa as coisas mais “desorganizadas” e “sem padrão)
- quando for trabalhar com banco de dados, deve-se otimizar ao máximo o espaço utilizado, e é muito comum que os programadores (ao menos eu) armazenem apenas o nome do arquivo e nao sua extensão, pois presume-se que as extensões serão sempre as mesmas (ou separa por pasta com a extensão, sei lá, mas pense sempre em manter tudo organizadinho para quando for necessário uma manutenção não ficar perdendo horas com problemas de organização (que acriditem, são muito constantes e chatos de resolver))
- eu particularmente, utilizo a função “mktime()” para gerar os nomes dos arquivos e nunca tive problemas, mas lembre-se de, caso o sistema tenha a possibilidade de ter muitos usuários simultâneos enviando arquivos, concatenar algo ao nome do arquivo, evitando assim replicação de arquivos
lembre-se que isso são apenas minhas dicas, não estou obrigando ninguém a segui-las ;)
12 | if(move_uploaded_file($_FILES['arquivo']['tmp_name'], $pasta."/".$nome)) |
nessa linha é que está todo o “trabalho” :D
a função “move_uploaded_file()” move um arquivo (vindo de um formulário) de um lugar para o outro, no nosso caso, estamos movendo o arquivo temporario criado pelo PHP para a pasta que nós queremos e deixando o nome original do arquivo (mas poderíamos facilmente especificar o nome e extensão desejadas, como por exemplo, utilizar a função “mktime()” para gerar nomes que (praticamente) nunca se repitam (pois podem haver múltiplas pessoas enviando arquivos no mesmo segundo, e devemos estar “prontos” para lidar com isso))
13 14 15 16 17 18 19 | { echo "Arquivo movido"; } else { echo "Falha ao mover arquivo"; } |
aqui apenas estamos mostrando uma mensagem de sucesso ou erro, acho que não tem muito o que explicar ;)
agora, além de enviar os arquivos, devemos mostra-los para que a pessoa possa ve-los em outra página, para isto, já fiz um tutorial que se chama Mostrando o Conteúdo de Pastas/Diretórios com PHP e que ensina passo-a-passo como mostrar os arquivos contidos em uma pasta (que é exatamente o que queremos)
manuais da W3C:
Especificação sobre Formulários, Especificação sobre o “enctype”
referência das funções:
“move_uploaded_file()“, “mktime()”
bom, fico por aqui com este tutorial, até a próxima
e lembre-se : problemas? reporte; dúvidas? pergunte :D
38 Responses to “Upload de arquivos com PHP”
By Roger on jan 27, 2009 | Reply
Muito obrigado .. depois de muita coisa que não funcionava achei teu site e consegui enfim fazer o dito formulário funcionar .. O legal é que depois da explicação fica fácil implementar controles por extensão, tamanho etc .. valeu mesmo
Quote
By DragaO~ on jan 27, 2009 | Reply
fico feliz que este post tenha te ajudado
espero que ajude muitas outras pessoas que ainda têm dúvidas em relação à isso :D
obrigado pelo comentário e volte sempre ;)
Quote
By SaMuCaO on fev 6, 2009 | Reply
Cara, ralei pra caramba pra achar algo que fucionasse, e finalmente encontrei…
MUITO OBRIGADO!!!
Quote
By DragaO~ on fev 9, 2009 | Reply
São comentários como esses que nos deixam felizes por postar material no blog :D
Ainda bem que achou o que procurava, espero que continue frequentando o blog ;)
Quote
By Rafael on fev 11, 2009 | Reply
cara muito bom… muito bom mesmo… espero que continue sempre postando… não é sempre que encontro material de qualidade publicado na web.
Quote
By DragaO~ on fev 12, 2009 | Reply
Obrigado pelo elogio, fico feilz que tenha gostado do material.
Continuarei postando sim, aliás, estou terminando um material que venho desenvolvendo desde o início do ano, espero que o pessoal aprove ele assim como tu aprovou esse.
Espero sua visita no(s) meu(s) próximo(s) post(s) :D
Quote
By Luciano on fev 14, 2009 | Reply
Olá, tenho recebi um denie ao tentar fazer o up do arquivo, já alterei permissões na pasta do script e do destino mas nada funfou, o que seria possível?
Warning: move_uploaded_file(/diretorioDefinidoNoPhp.ini/arquivo.jpg) [function.move-uploaded-file]: failed to open stream: Permission denied in /diretorioDoArquivoPhpNaPastaDoServidor/upload001.php on line 12
Warning: move_uploaded_file() [function.move-uploaded-file]: Unable to move ‘/tmp/phpeliLmj’ to ‘/diretorioDefinidoNoPhp.ini/arquivo.jpg’ in /diretorioDoArquivoPhpNaPastaDoServidor/upload001.php on line 12
[]’s
Luciano
Quote
By DragaO~ on fev 16, 2009 | Reply
Boa tarde,
Vejo que estes erros não são os “originais”, mas vamos lá ;)
Qual seria a pasta “diretorioDefinidoNoPhp.ini”? Pode ser que seja apenas problema de configuração mal-feita (sem querer ofender ninguém)
Outra coisa, verifique não somente as permissões (na maioria das vezes “0755″ resolve), mas também o owner (”dono”) e group (”grupo”) da pasta, bem como a(s) pasta(s)-pai.
Obrigado pelo comentário :D
Quote
By Luciano on fev 17, 2009 | Reply
legal as dicas…consegui, mas não era problema de permissões nem configs…somente de indicar de forma errada o caminho dos uploads…
de qq forma, muito obrigado e parabéns pelos post!!!
[]’s
Luciano
Quote
By DragaO~ on fev 17, 2009 | Reply
Essa foi a primeira coisa que eu havia pensado, porém, como vi que tu havia “escondido” as pastas, achei que elas estavam corretas.
Mas em todo caso, fico feliz que tenha resolvido seu problema ;)
Obrigado pelo elogio e volte sempre :D
Quote
By inacio on mar 4, 2009 | Reply
amigo, tu me ajudou resolver meu problema com seu artigo, desejo que continue e não desista de seu blog.
felicidades !!!
Quote
By DragaO~ on mar 4, 2009 | Reply
Fico feliz de ter conseguido te ajudar, e espero que tenha aprendido (nem que seja um pouquinho) com este post, assim fico mais feliz ainda :D
Obrigado, continuarei mantendo o blog, e espero que você seja um dos visitantes, afinal, é graças a pessoas como tu que eu ainda nao desisti dele :)
Quote
By Everton on mar 7, 2009 | Reply
Valeu amigo! Até agora foi o único script que realmente funcionou! Show de bola! Muito obrigado!!!!!!
Quote
By DragaO~ on mar 7, 2009 | Reply
Que bom que funcionou pra ti, espero que tenha lido e aprendido como se faz, e não apenas copiado ;)
Obrigado pelo comentário e espero vê-lo novamente por aqui :)
Quote
By Matheus on mar 25, 2009 | Reply
Parabéns, DragaO~ mto bom seu tuto, me ajudo bastante…
Vlw mesmo!!!
Quote
By DragaO~ on mar 25, 2009 | Reply
obrigado pelo elogio, espero que continue acompanhando o blog :)
Quote
By bruno rios on mai 27, 2009 | Reply
e aí dragao blz? valew pelo tutorial, excelente!
e para enviar dois ou mais arquivos?
como faço?
abraço!
Quote
By bruno rios on mai 27, 2009 | Reply
consegui enviar multiplos arquivos…
se alguem quiser a dica…
Quote
By Augusto on jun 26, 2009 | Reply
Esse script funciona em servidor local? Porque aqui eu executo e nada acontece… nem o que está no comando echo do arquivo php é exibido.
Quote
By Augusto on jun 26, 2009 | Reply
Ah, só complementando, dos scripts que vi por aí, este foi o que está mais fácil de entender. ^^
Mesmo que não tenha funcionado aqui, fica meus agradecimentos pela iniciativa.
Quote
By DragaO~ on jun 30, 2009 | Reply
você se refere aos “echos” do arquivo “envia_arquivo.php”? se sim, altere o arquivo e adicione alguns “echo” para descobrir onde a execução do arquivo não está indo; algo como isso :
e poste os resultados aqui :)
obrigado pelo elogio ^^
Quote
By MarcosCB on jul 7, 2009 | Reply
Olá… excelente post. Me ajudou em uma dúvida cruel! Obrigadissimo e continue assim! Pessoas como você que nos faz entrar na internet e conseguir achar tudo (ou quase tudo) que precisamos.
Agora um pequena dúvida e curiosidade: como e por que você utiliza a função mktime()para gravar o nome de seus arquivos? Pode mostrar um exemplo de como faz?
Agradecido!
Quote
By DragaO~ on jul 8, 2009 | Reply
fico feliz por poder ajudar :D
eu uso o mktime assim ó:
perceba a função “mktime()” na linha 10 e a função “strrchr()” na linha 12
a função “mktime()“, como eu disse anteriormente, nos retorna o número de segundos desde 1 de janeiro de 1970, portanto, a cada segundo ele nos retorna um número (inteiro) diferente fazendo com que, se o sistema não for muito acessado simultâneamente isso nos serve perfeitamente (se ele fosse, bastaria verificar a existência de um arquivo com o nome selecionado, e, caso existisse, bastava concatenar uma string aleatória “a mais” no mktime e pronto :D)
a função “strrchr()” nos retorna a última parte de uma sting após, no nosso caso, o “.” (ponto final). Com isto podemos pegar a extensão do arquivo.
Veja que nesse exemplo, o usuário poderia, por exemplo, enviar um arquivo executável (comumente com extensão “.exe”) apenas mudando sua extensão para outra coisa, como por exemplo “.jpg”, e o sistema “entenderia” que o arquivo se trata de um arquivo de imagem legítimo, por isso não aconselho a fazer verificações de arquivos baseando-se na extensão de um arquivo, para isso utilize o mimetype do arquivo, fornecido na posição “type” do array “$_FILES” (faça um exemplo funcional de upload e dê um “echo” na variável “$_FILES['arquivo']['type']” e veja o que ele te retorna para entender melhor)
não sei consegui esclarecer a tua dúvida, mas qualquer coisa, torne a perguntar :D
referência das funções:
“mktime()“, “strrchr()”
Quote
By Marcelinho on jul 8, 2009 | Reply
Ótimo post, tenho certeza que vai me ajudar bastante…
Mais só duas dúvidas, se fosse multiupload, é só acrescenter o [] no nome do input, assim?
E como ficaria no arquivo q faz o upload? Precisaria mudar algo?
E a outra é se eu quisesse gravar o caminho onde o arquivo foi salvo pro MySQL, qual seria a melhor opção?
Poderia ser assim?
$fotoperfil = “$pasta/$nome”
E logo em seguida o código pra dar o Update, tipo
UPDATE usuarios SET fotoperfil = ‘$fotoperfil’ …
Quote
By Marcelinho on jul 8, 2009 | Reply
E só mais uma coisinha…rsrs
Tem como por exemplo quando fizer o upload ele redimensionar a imagem? Tipo se a imagem está em 1024×768 e eu quiser deixa-la em 640×480 como eu faria?
Obrigado, desculpe pelas perguntas é q ainda estou aprendendo php e nunca fiz um curso pois aki na minha cidade nao oferece e na net eles cobram muito caro por isso!
E parabéns pelo blog!
Quote
By Marcelinho on jul 11, 2009 | Reply
Me ajudou bastante amigo, ótimo tutorial muito bem explicado, mais eu faria se fosse upload multiplo?
Quote
By DragaO~ on jul 13, 2009 | Reply
desculpe a demora em responder, semana que provas fica complicado ;x
basicamente, sim :D
precisaria sim, mas não seria muita coisa; bastaria tu adicionar um laço para percorrer todas as posições do array “$_FILES”, algo assim :
html:
teríamos, algo mais ou menos asim :
“$_FILES['arquivo'][VALOR][0]” e “$_FILES['arquivo'][VALOR][1]”
onde “VALOR” seria o que tu quer pegar daquele arquivo (”name”, “type”, “tmp_name”, etc)
entao, tu poderia fazer algo assim:
não sei se deu pra entender, mas qualquer coisa, fala :D
se tu fizesse o upload do arquivo todo corretamente, bastaria apenas tu armazenar o nome do arquivo e colocar no MySQL sim
não seria necessário o nome da pasta, pois, na grande maioria dos casos, tu (programador) “decide” isso diretamente pela estrutura de arquivos, mas se tu te sentir mais à vontade, pode colocar o nome da pasta no banco sim, porém, acho que isso poderia complicar um pouco (sem contar que cresceria o tamanho do banco)
isso é um pouco complicado, mas já aviso que tu vai precisar da extensão “gd” habilitada no servidor (o que não é nem um pouco dificil de habilitar, seja em windows ou linux)
infelizmente eu ando em período de provas e, por ser longa a explicação, acho que ficaria melhor eu explicar isso num post
se tu estiver precisando muito disso, recomendo dar uma olhada nesses links que achei :
esse me pareceu o mais explicado, esse me pareceu o mais complexo (com mais coisas), esse me pareceu bom, mas com poucos comentários no código
no mais, não prometo, mas acho que assim que der, faço um post sobre manipulação de imagens com PHP :D
mas sinta-se à vontade para perguntar alguma eventual dǘvida sobre manipulação de imagens (minhas provas terminam daqui uma ou duas semanas, até lá, posso demorar)
não se desculpe pelas perguntas, sinta orgulho delas, afinal, você teve coragem o suficiente em perguntar (ou tu nunca viu gente ficar com dúvida a vida toda por ter vergonha de perguntar?)
boa sorte com os estudos :)
Quote
By wadson on jul 31, 2009 | Reply
boa noite dragão…
parabéns pelo blog..otimas dicas
mais é o seguinte.. preciso da sua ajuda…
no meu form aparece echo ‘ falha ao mover o arquivo constantemente… copiei o codigo conforme vc postou…
poderia me dar uma dica do que pode ser? já tentei quase tudo…rsrs..
um abraço
Quote
By DragaO~ on ago 10, 2009 | Reply
acho que, provavelmente, a pasta “uploads” não existe, por isso deve estar dando esse erro.
também pode ser o caso de ser um arquivo muito grande, qual o tamanho do arquivo que tu está testando?
aliás, de nada adianta tu copiar todo o código sem entender o que ele faz, afinal, a minha meta não é ser um “laboratório de scripts”, mas sim ensinar (ou ao menos tentar XD) as pessoas como fazer certas coisas
creio que, se tu tivesse aprendido algo, tu saberia resolver um possível problema desse tipo (a não ser claro, que seja um problema incomum ou de configuração/permissão no php)
ignore isso caso tu não tenha simplesmente “copiado e colado” :)
Quote
By Guidje on out 21, 2009 | Reply
hahaha… genial!!
cara, brigadão!! perfeito!! não só o código funcionou como entendi o conceito (o q é o mais importante, né??)
abraço!!!
Quote
By Claudio Sanches on mar 18, 2010 | Reply
Gostei muito, o único que funcionou.
Porém gostaria de saber, teria como colocar o código certinho de como deveria colocar para fazer upload multiplos? tentei fazer o lance dai de cima que você explicou para o Marcelinho, mas mesmo assim não tive sucesso.
Quote
By DragaO~ on mar 19, 2010 | Reply
basicamente, é aquilo ali que eu disse pra ele, seria apenas pegar os códigos, talvez modificar um pouco dependendo da tua realidade, e usar; sem complicações.
o que tu não entendeu do que eu disse pro marcelinho? acho que te ajudar mais especificamente seja melhor do que te dar um código e dizer “cola aí” :)
Quote
By Alexandra on mar 23, 2010 | Reply
Oi DragaO~, parabéns pela didática, estava há muito tempo procurando uma rotina igual a esta. Mas ao testar deu o erro “Falha ao mover arquivo”. A única mudança que fiz foi criar a pasta uploads dentro de uma pasta de nome up, então montei a variável $pasta = “up/uploads”. A pasta up está na raiz. Fiz algo errado? Agradeço se puder me ajudar.
Um grande abraço.
Quote
By DragaO~ on abr 8, 2010 | Reply
À princípio eu diria que tu não errou em nada, mas, em todo caso, eu peço que coloque aqui todo o código que tu tens, para ver se existe um erro nele ou se é com o servidor mesmo.
No mais, desculpe a demora em responder (creio que tu até já tenha resolvido esse teu problema, mas em todo caso…)
Quote
By pSy on ago 26, 2010 | Reply
Caríssimo blogueiro.
Estou entrando neste blog para parabenizá-lo pelo ótimo código, muito obrigado por postar este material. Funcionou perfeitamente.
Se não fosse pedir demais, eu gostaria de enviar arquivos grandes com este seu script, mas não estou entendendo como deveria fazer.
Já alterei as linhas no meu php.ini para o valores abaixo, mas eu continuo só upando arquivos de 8M no máximo.
php.ini -> upload_max_filesize = 8000M
php.ini -> post_max_size = 8000M
php.ini -> max_execution_time = 3000
Abração…
Quote
By Jean on set 2, 2010 | Reply
Amigo obrigado!!estava ficando maluco, seu script funcionou de boa!!! ainda bem que existem pessoas como vc!!
Valeu mesmo!!!
Quote
By DragaO~ on set 3, 2010 | Reply
@pSy
Obrigado :D
sobre teu problema, tu realmente precisa de 8 Gb e 3 mil segundos? se não precisar, tenta mudar pra alguns valores mais baixos, tipo 200M e 300 segundos.
e, claro, não se esqueça de reiniciar o servidor web :)
Quote