Translate this page now :



»Programação
»Programação.NET
»Banco de Dados
»Webdesign
»Office
» Certificações Microsoft 4
»Treinamentos4
»Programação 4
»Webdesign«
»Office & User Tips«
»Grupos de Usuários
»Células Acadêmicas«
intcontpiada : 118
Viciado
Você já está cadastrado e participa do grupo de usuários de sua cidade ? Se não, comente o porque.
 
 
Faça um pequeno teste com 10 questões de VB
.:.
Teste seus conhecimentos em Visual Basic, SQL Server e ASP 3.0 com nossas provas on-line
.:.
Aprimore seus conhecimentos em programação com nosso treinamento on-line de lógica de programação
.:.
Veja nosso calendário de treinamentos
Gostou da Página?
Então

para um amigo!
 







Pesquisa personalizada
Pesquisar Dicas:

 







Quer saber mais?
Não deixe escapar essa oportunidade!
Faça um treinamento para Webdeveloper na Búfalo Informática

 

Upload de Arquivos apenas com código ASP


Uma das piores omissões na versão mais antiga do ASP é a habilidade de tratar um arquivo que tenha sido postado a partir de um formulário HTML. Enquanto que o objeto REQUEST do ASP sempre pode acessar qualquer outro tipo de campo de formulário, arquivos postados sempre estiveram fora dos limites do ASP. A solução usual é implementar o suporte a upload utilizando o Posting Acceptor ou um componente de terceiros. Neste artigo vamos ver como é simples contornar esta limitação e recuperar arquivo (ou arquivos!) dos dados postados para um arquivo ASP.

Primeiro, fazendo um upload

A primeira necessidade deste processo é ter um formulário HTML que faça upload de arquivo para uma página ASP. Veja o formulário abaixo :

<html>
   <head>
   <title>Upload de Arquivos com ASP!</title>
   </head>
<body>
   <form action="filePost.asp" enctype="multipart/form-data" method="post" name="f" id="f">
	   Escolha um arquivo para o upload:<br />
	   <input type="file" name="test" size="50" />
	   <br />
       <input type="submit" value="submit" />
   </form>
</body>
</html>

Observe que o formulário precisa ter o atributo enctype definido como"multipart/form-data". Este é o schema de enconding necessário quanto estamos transmitindo um arquivo para o servidor.

Próximo passo, salve o arquivo

A segunda parte do processo é um pequeno truque, mas com um pouco de cuidado,você verá que não é terrivelmente difícil.

Para salvar o arquivo no servidor criei uma classe de script chamada cla_upload, simplificando assim o seu uso. Se desejar saber mais sobre classes de script leia nosso artigo sobre Criação de classes em ASP.

O código possui dois métodos públicos, processaUpload e SalvarArquivos. Desta forma a operação de identificar os arquivos recebidos e salva-los no disco do servidor foi dividida em duas etapas, o processamento e o momento de salvar os arquivos.

Após o processamento os arquivos e demais informações que tenham sido postadas são mantidas em variáveis da classe. No caso das demais informações postadas elas são expostas através da propriedade Variaveis.

Como a classe precisa de algumas variáveis pré-definidas foi criado um class_initialize que inicializa, por exemplo, a variável crlf.

Veja o código da classe :

<%
Class cla_Upload
Dim myRequest,myRequestFiles,tmpRequestFiles
   dim crlf
   Dim bJaProcessou
Public property get Variaveis(sVariavel)
   on error resume next
   if bJaProcessou then
   Variaveis=myRequest(sVariavel)
   end if
   end property
   Public Sub ProcessaUpload()
 if bJaProcessou then
   'erro 
   exit sub
   end if
 'Altera o tempo de processamento para arquivos grandes
   Server.ScriptTimeout = 5400
 Const ForWriting = 2
   Const TristateTrue = -1

 'Recupera os dados postados na forma binária
   PostData = ""
   Dim biData
   biData = Request.BinaryRead(Request.TotalBytes)
   'Transforma os dados da forma binária para algo mais legível
   For nIndex = 1 to LenB(biData)
   PostData = PostData & Chr(AscB(MidB(biData,nIndex,1)))
   Next
   'Recupera o content type para determinar o encoding dos dados
   ContentType = Request.ServerVariables( _
   "HTTP_CONTENT_TYPE")
   ctArray = Split(ContentType, ";")
 'Se o encoding for 
   '"multipart/form-data", então foi feito upload, damos sequencia    ao processamento
   If Trim(ctArray(0)) = "multipart/form-data" Then
   ErrMsg = ""
 ' Obtem o boundery, o separador de variáveis utilizado na transmissão
   bArray = Split(Trim(ctArray(1)), "=")
   Boundary = Trim(bArray(1))
 'Usa o Boundary para separar todas as variáveis
   FormData = Split(PostData, Boundary)
 'Criação de 3 scripting.dictionary que guardarão as informações
 
 Set myRequest = CreateObject("Scripting.Dictionary")
   set myRequestFiles=CreateObject("Scripting.Dictionary")
   
   FileCount = 1
   For x = 0 to UBound(FormData)
   set tmpRequestFiles=CreateObject("Scripting.Dictionary")
 'Faz a localização de dois caracteres crlf que
   'Marcam o fim dos metadados do campo e inicio dos dados propriamente
 InfoEnd = InStr(FormData(x), CrLf & CrLf)
   If InfoEnd > 0 Then
   'Pega as informações sobre o campo
 varInfo = Mid(FormData(x), 3, InfoEnd - 3)
 'Pega o valor do campo, evitando os 2 crlf no inicio
   'e o crlf que encontra-se no final
 varValue = Mid(FormData(x), InfoEnd + 4, _
   Len(FormData(x)) - InfoEnd - 7)
 'Verifica se trata-se de um arquivo ou de uma variável qualquer
   If (InStr(varInfo, "filename=") > 0) Then
   
   'Monta um script dictionary com as informações sobre o arquivo
   
   
   tmpRequestFiles.add "nome",GetFieldName(varInfo)
   tmpRequestFiles.add "conteudo",varValue
   tmpRequestFiles.add "filename",GetFileName(varInfo)
   tmpRequestFiles.add "filetype",GetFileType(varInfo)
 'Insere o script dictionary montado dentro de outro, contendo
   'Todos os arquivos que levaram upload
 MyRequestFiles.ADD "arq" & FileCount,tmpRequestFiles
   
   FileCount = FileCount + 1
   Else
   'É um campo comum
   myRequest.add GetFieldName(varInfo), varValue
   End If
   End If
   Next
   Else
   ErrMsg = "Falha no Encoding Type!"
   End If 
   bjaprocessou=true
   End Sub
   Sub class_Initialize
   bJaprocessou=false
   CrLf = Chr(13) & Chr(10)
   end Sub
   Public Sub SalvarArquivos()
 dim icnt
   icnt=1
 do while icnt<=myRequestFiles.Count
   
   set tmprequestfiles=myrequestfiles.Item("arq" & icnt)
 Set lf = server.createObject("Scripting.FileSystemObject")
 ' para utilizar o nome do arquivo original é necessário 
   'determinar que tipo de client enviou o arquivo.
   'clientes Macintosh enviam apenas o nome do arquivo
   'sem path, enquanto clientes Windows 
   'enviam o caminho inteiro do arquivo selecionado
   
   BrowserType = UCase(Request.ServerVariables( "HTTP_USER_AGENT"))

   If (InStr(BrowserType, "WIN") > 0) Then
	   'Sendo Windows, obtem o nome do arquivo do final do path
	   sPos = InStrRev(tmprequestfiles("filename"), "\")
	   fName = Mid(tmprequestfiles("filename"), sPos + 1)
   End If
   If (InStr(BrowserType, "MAC") > 0) Then
	   'Neste caso apenas o nome do arquivo foi recebido
	   fName = tmprequestfiles("filename")
   End If
   'se fizer um upload para um caminho diferente, altere aqui
   FilePath = "/global/Upload/" & fName
   SavePath = Server.MapPath(FilePath)
   Set SaveFile = lf.CreateTextFile(SavePath, True)
   SaveFile.Write(tmprequestfiles("conteudo"))
   SaveFile.Close
   icnt=icnt+1
   loop
End Sub
   'Esta função recupera o nome de um campo
   Private Function GetFieldName(infoStr)
	   sPos = InStr(infoStr, "name=")
	   EndPos = InStr(sPos + 6, infoStr, Chr(34) & ";")
	   If EndPos = 0 Then
		   EndPos = inStr(sPos + 6, infoStr, Chr(34))
	   End If
	   GetFieldName = Mid(infoStr, sPos + 6, endPos - (sPos + 6))
   End Function
'Esta função recupera o filename de um arquivo
   Private Function GetFileName(infoStr)
	   sPos = InStr(infoStr, "filename=")
	   EndPos = InStr(infoStr, Chr(34) & CrLf)
	   GetFileName = Mid(infoStr, sPos + 10, EndPos - (sPos + 10))
   End Function
'Esta função recupera o MIME type de um arquivo
   Private Function GetFileType(infoStr)
	   sPos = InStr(infoStr, "Content-Type: ")
	   GetFileType = Mid(infoStr, sPos + 14)
   End Function
End Class
   %>

Vamos analisar cada um dos métodos da classe, iniciando-se pélo PROCESSAUPLOAD

Este script inicia-se dando ao servidor um tempo generoso de processamento,qualquer que seja o arquivo que esteja sendo uploadeado. Isso é uma consideração muito importante, porque o servidor pode levar muito tempo para processar um arquivo grande. Se o seu script gerar timeout antes do processo terminar, o arquivo uploadeado será perdido.

Pegar o POST

A primeira coisa que o script faz é recuperar todos os dados que são postados do arquivo HTML e inseri-los em uma variável chamada biData. Isso é feito utilizando o método BinaryRead do objeto Request. Como o nome já diz, esse método lê um número especificado de bytes do objeto request, de forma binária. O número de bytes a ser lido é fornecido pela propriedade Totalbytes do objetoRequest.

Uma interessante consequencia do método BinaryRead é que, uma vez utilizado,você não pode mais acessar o conteudo do Request.Form ou Request.Querystring. O resultado inesperado disso é que se você acessar o request.form ou request.querystring não poderá utilizar binaryRead em seguida. Isso significa que você não pode misturar esses dois métodos de recuperar informações postadas.Consequentemente, se você postar outros dados juntamente com o arquivo você terá que extrai-los do meio dos dados postados manualmente.

Por causa disso a classe implementa a propriedade variáveis. Quando um formulário fizer post de arquivos e outros dados em conjunto, poderá (deverá) utilizar a classe tanto para salvar os arquivos como para recuperar os demais dados postados.

Antes de começar a extrair as informações, porém, você tem que transformar todos os dados binários em algo mais amigável. Olhando a listagem, logo abaixo da chamada dométodo BinaryRead, você vê um loop simples que faz exatamente isso. Esse loop simples utiliza uma série de funções para manipulação de dados em binário para converter os dados para um formato mais facilmente legível e inserir os dados navariável PostData (Observe que você não deverá fazer isso para todos os tipos dearquivos uploadeados. Mas você ainda tem acesso aos dados binários na variávelbiData caso precise).

Quebrar os dados é fácil

Uma vez que os dados foram postados em formato ASCII, é um processo simples trabalhar estas informações e extrair cada campo das informações. O primeiro passo é determinar se seus dados estão utilizando o encoding correto. Depois disso, devemos determinar qual o separador (boundery) está sendo utilizado entre cada elemento de formulário.

Para nossa conveniência ambas as informações podem ser encontradas em um mesmo lugar : no cabeçalho HTTP_CONTENT_TYPE (sim, você ainda tem acesso a ele mesmo depois de utilizar BinaryRead. Você apenas não pode utlizar Request.form e request.QueryString). Como você pode ver, a estrutura desta informação é bem simples :

multipart/form-data; boundary=----------
-----------------
7d117c2c490276

Dada esta estrutura simples, é fácil extrair a informação que você precisa.Primeiro nós utilizamos a função Split para quebar a informação em torno do ponto e virgula. Isso permite checarmos o tipo de encoding facilmente apenas checando o primeiro elemento do array criado pela chamada da função split. Assumindo que o encoding type é o que esperamos ("multipart/form-data"), nós extraimos o separador (boundary) utilizando outra chamada a função split.

Agora que temos o separador, tudo que precisamos fazer é outra chamada a função Split.

Claro, ainda temos um pouco mais a fazer. Cada divisão de dados do form tem, por si só, duas divisões. Na primeira encontramos informações sobre o campo (o nome do campo e outras informações associadas). A segunda divisão contém os dados que foram transmitidos. Veja um exemplo de como isso fica :

-----------------------------7d117c2c490276
Content-Disposition: form-data; name="test"; filename=
"C:\testDoc.txt"
Content-Type: text/plain

test upload file.
-----------------------------7d117c2c490276
Content-Disposition: form-data; name="filename"

userSpecified
-----------------------------7d117c2c490276
Content-Disposition: form-data; name="userSpecifiedName"

Test.txt
-----------------------------7d117c2c490276--


Como você pode ver nesta listagem, o separador é usado para separar cada campo(e seus dados) dos demais. Infelizmente a divisão de informações de um campo (onome do campo) não é separada de sua divisão de dados por nada óbvio. Bem, na verdade, é óbvio, mas nos acostumamos tanto a ignorar esse separador que fica difícil de notar. Basicamente, são dois pares de enter e line feed (chr(13) echr(10) ) separando as duas divisões de dados. Temos assim um total de 4 bytes usados como separadores.

Separando os dados do formulário

Agora será ótimo se nós pudermos extrair todos esses dados do formulário em uma coleção simples, tal como a request.Form. Então, com isso em mente, a listagem define três coleções, myRequest, MyRequestFiles e tmpRequestFiles (definidas a nível de classe para que os dados sejam mantidos entre os métodos).

Para poder guardar os dados dos arquivos uploadeados em coleções torna-se necessário que cada item da coleção seja na verdade uma outra coleção. Isso porque cada arquivo gera um série de informações.. Por exemplo, pode ser necessário tratar o nome do camo postado, oconteúdo do arquivo transmitido, o nome/caminho do arquivo (onde estava no client), o MIME type do arquivo, etc.

Por isso utilizamos a variável tmpRequestFiles como uma coleção de dados de um arquivo durante o processo de extração das informações e ao terminarmos de obter as informações deste arquivo inserimos esta variável dentro de MyRequestFiles. Assim sendo cada item de myRequestFiles é na verdade uma coleção dos dados de um arquivo.

Neste ponto, é simples realizar um loop através de todos os campos do formulário contidos no vetor no qual postData foi dividido pelo separador. Cada campo é examinado, a informação e os dados são extraidos utilizando chamadas simples para a função Mid. Observe que não utilizamos split aqui. Isso porque também podem haver duplos CRLF dentro da informação que foi postada.

Depois que essas informações são extraidas, a primeira divisão é examinada para verificar se contém a string "filename=". Se contém, então trata-se de um arquivo uploadeado. Neste caso, chama-se várias funções, definidas no topo do código, para extrair o nome do campo, nome do arquivo e MIME type do arquivo. Essas informações são então acrescentadas, junto com o conteúdo do arquivo em si, no array de arquivos uploadeados.

Se o campo não é um arquivo, o nome é extraido utilizando a função GetFieldName e o nome e conteúdo é adicionado na colecão MyRequest.

É isso ! Com o loop terminando, a coleção myRequest contem todos nossos campos de formulário normais enquanto que o array myRequestFiles contém até 10 arquivos uploadeados. Se precisa de mais de 10 arquivos, apenas mude as dimensões doarray.

Ok, Agora salve os arquivos

Neste ponto, tudo o que sobre é realmente salvar o arquivo (ou os arquivos) que foram uploadeados no servidor. Para este fim temos o método SalvarArquivos que faz um loop na coleção myRequestFiles salvando cada um dos arquivos uploadeados. É importante observar que para que a operação funcione a conta de anônimo do IIS precisa ter permissão de escrita no diretório onde você deseja salvar o arquivo.

Deve-se lembrar também que upload é uma operação perigosa. Se alguém fizer um upload de um .asp ou .exe e o diretório que recebe os uploads não estiver configurado corretamente (no caso, para ignorar esses arquivos) pode-se causar um grande estrago ao servidor.

Veja um pequeno exemplo de uso desta classe (o código do arquivo que estará recebendo o post):

<!--#include file="upload.asp"-->

<%

dim x as cla_upload
x.processaupload()
x.salvararquivos()
set x=nothing
response.redirect("sucesso.asp")%>

 

Dennes Torres
MCSD,MCSE,MCDBA

 



� Búfalo Informática, Treinamento e Consultoria - Rua Álvaro Alvim, 37 Sala 920 - Cinelândia - Rio de Janeiro / RJ
Tel.: (21)2262-1368 (21) 9240-5134 (21) 9240-7281 e-Mail:
contato@bufaloinfo.com.br