In molte occasioni sviluppando applicazioni Web ci si imbatte nella necessità di dover dare la possibilità agli utenti che utilizzano il web di spedire un file dal suo PC direttamente al server. Questa operazione in gergo viene definita UPLOAD.
Normalmente per implementare questa funzionalità ci si deve servire di componenti esterni che vengono eseguiti sul server. Purtroppo però questi componenti, oltre che avere un costo, necessitano di un'installazione da parte del fornitore di servizio sulle sue macchine; cosa che non sempre, anzi, molto raramente, avviene.
In questo articolo cercheremo di capire come effettuare le operazioni di upload senza utilizzare nessun componente esterno, ma servendoci unicamente degli strumenti messi a disposizione dal linguaggio.
Di cosa abbiamo bisogno
Beh, davvero di poco! Le condizioni da soddisfare in linea di massima sono 2:
- avere un file da caricare
- avere un posto dove metterlo
Per la prima condizione mi sembra davvero inutile aggiungere altro.
Per la seconda invece è fondamentale che lo spazio web a nostra disposizione abbia una cartella dove sono stati abilitati i permessi di scrittura in modo da poter posizionare i file che vengono uploadati.
Normalmente tutti gli spazi web comprendono una cartella che risponde a questi requisiti ma nel caso in cui quest'ultima non ci fosse, potete contattare il vostro fornitore di servizio e chiedergli di creare una cartella ed assegnarle i permessi di scrittura.
Spedire i dati (form.html)
Iniziamo dalla parte più semplice: recuperare i dati e spedirli. Dobbiamo dare la possibilità all'utente di inserire i dati, scegliere il file da spedire e inviarlo al server.
Per adesso potremmo dare la possibilità all'utente di spedire unicamente il file e un campo di testo ma in ogni caso si può anche inviare altro, come altri campi di testo, checkbox, e simili in modo da poterli utilizzare in seguito per essere inseriti in un database o semplicemente di visualizzati. Per fare questo ci serviremo di un semplice form.
<form action="upload.asp" method="post" enctype="multipart/form-data"> CAMPO TESTO <input type="text" name="testo1"> FILE <input type="file" name="file1"> <input type="submit" value="Upload"> </form>
Come potete notare è un semplice form che chiama una pagina (upload.asp
) dove verranno inserite le operazioni da effettuare.
N.B. Il form deve essere di tipo multipart/form-data condizione richiesta affinché vengano passati effettivamente i dati. Se noi impostassimo nel form unicamente il metodo POST senza specificare il tipo di formato verrebbe passato il valore contenuto nel campo file del form, e quindi unicamente il percorso del file ma non i dati in esso contenuti.
Recuperare i dati (upload.asp)
A questo punto i dati sono stati spediti dal PC client verso il server dove a loro volta dovranno essere recuperati. La prima cosa da verificare è quanti dati sono stati spediti dal client. Il recupero di qualsiasi informazione in ASP viene effettuato tramite l'oggetto Request ed i suoi metodi.
<% DatiRicevuti = Request.TotalBytes %>
Request.TotalBytes ci permette di conteggiare il numero totale dei byte che sono stati inviati tramite il form. Nel caso in cui volessimo visualizzare quanti dati sono stati spediti potremmo fare
<% DatiRicevuti = Request.TotalBytes Response.Write DatiRicevuti %>
Adesso sappiamo che i dati sono passati dal client al server ma in questo modo vengono solo conteggiati e non effettivamente elaborati. Per recuperarli effettivamente ci serviremo sempre dell'oggetto Request di ASP e di un altro particolare metodo di utilizzo : il BinaryRead.
Il metodo BinaryRead legge un certo numero di byte direttamente dal corpo della richiesta http inviato dal client come parte del metodo post. Il suo utilizzo:
variabile = Request.BinaryRead(numero_di_byte_da_leggere)
In questo caso dovendo leggere l'intero file e non solo una parte, non resta che conteggiare quanti byte sono stati spediti e memorizzarli in una variabile che sarà il nostro file:
<% DatiRicevuti = Request.TotalBytes File = Request.BinaryRead(DatiRicevuti) %>
Nel caso in cui volessimo visualizzare quali dati sono stati spediti
potremmo fare:
<% DatiRicevuti = Request.TotalBytes File = Request.BinaryRead(DatiRicevuti) Response.BinaryWrite File %>
Ottenendo un risultato simile a questo:
-----------------------------7d21222e60 Content-Disposition: form-data; name="testo1" davide-----------------------------7d21222e60 Content-Disposition: form-data; name="file1"; filename="C:WINDOWSDesktoptest.gif" Content-Type: image/gif GIF89a22æ':[2á>|¯è÷"Eê [1] &möüy|Ã"óoÊYE?lÄïV?$c[¿~åÿ1êòbÃÃ>^"*‑|D¡ïfÃŒ|éø
Questo significa che è stato ricevuto qualcosa, quindi è gia possibile fare un primo controllo in modo da iniziare a far prendere forma a quello che sarà lo script definitivo.
<% ' Recupero il numero di byte ricevuti DatiRicevuti = Request.TotalBytes ' Controllo che il numero di byte ricevuti sia > di 0 If DatiRicevuti > 0 Then ' Leggo i dati ricevuti File = Request.BinaryRead(DatiRicevuti) else ' Segnalo che non è stato ricevuto nulla Response.Write ("Non è stato inviato nessun file") End if %>
Intestazione del file
La serie di caratteri che è stata visualizzata, può apparire di scarso interesse, ma se viene analizzata meglio si può notare che non è altro che il nostro file con l'aggiunta di qualche informazione in più.
Quelle informazioni in più vengono raccolte nella prima e nell'ultima riga e costituiscono l'intestazione del file.
-----------------------------7d21222e60 Content-Disposition: form-data; name="testo1" davide -----------------------------7d21222e60 Content-Disposition: form-data; name="file1"; filename="C:WINDOWSDesktoptest.gif" Content-Type: image/gif
Analizzandole possiamo ottenere:
Frammento | Descrizione |
---|---|
------------7d21222e60 |
Identificativo del file spedito |
Content-Disposition: form-data |
Provenienza del file (form) |
name="file" |
Nome del campo del form |
filename="x:test.gif" |
Percorso e nome del del file |
Content-Type: image/gif |
Tipologia del file spedito |
Etc. |
Etc. |
Tutto quello che rimane (tolto l'identificativo di chiusura) è il contenuto del file vero e proprio.
Nota: È importante ricordare che si sta lavorando con dati di tipo binario quindi tutte le operazioni che verranno effettuate su di questi dovranno essere effettuate come binarie.
Ad esempio la funzione Mid che normalmente restituisce il numero di caratteri specificato di una stringa verrà utilizzata come MidB in modo da poterla utilizzare con i dati byte inclusi in una stringa. Gli argomenti di questa funzione specificheranno quindi il numero di byte anziché il numero di caratteri. Per recuperare queste informazioni quindi dobbiamo analizzare la prima riga di dati ricevuta.
<%
DatiRicevuti = Request.BinaryRead(ByteRicevuti)
For i = 1 To lenB(DatiRicevuti)
FileBinario = FileBinario & chr(ascB(midB(DatiRicevuti,i,1)))
Next
FirmaFile = left(FileBinario,instr(FileBinario,"" & vbCrLf)-1)
ArrPezzi = split(FileBinario,FirmaFile)
for pezzo = 1 to ubound(ArrPezzi)-1
Inizio = instr(ArrPezzi(pezzo),"" & vbCrLf & "" & vbCrLf)
Intestazione = left(ArrPezzi(pezzo),Inizio-1)
Inizio = Inizio + len("" & vbCrLf) + len("" & vbCrLf)
ContenutoFile = mid(ArrPezzi(pezzo),Inizio,len(ArrPezzi(pezzo))-Inizio-1)
' ...
In questo modo abbiamo tutto quello che ci serve non ci resta che controllare se gli altri campi spediti dal form contenevano qualcosa.
Per fare questo si deve utilizzare nuovamente la stringa di intestazione controllando gli altri campi quindi supponendo di dover controllare se un campo di testo del form denominato testo1 contiene qualcosa faremo:
if instr(Intestazione, "testo1") > 0 then text1 = ContenutoFile end if
e così via per tutti gli altri campi.
Scrivere il file
Per la scrittura del file utilizzeremo il FileSystemObject ormai abbiamo tutti i dati e non resta davvero altro da fare oltre che scrivere il file uploadato sul server in modo da completare le operazioni di upload.
Come al solito si effettua un controllo in modo da sapere se il campo del form che contiene il file (e che abbiamo chiamato file1
) effettivamente sia stato utilizzato:
if instr(Intestazione,"file1") > 0 then
dopo di che si cerca il nome nell'intestazione del file spedito:
i = InStr(Intestazione, "filename=") j = InStr(i + 10, Intestazione, chr(34)) NomeUpload = Mid(Intestazione, i + 10, j - i - 10) i = InStrRev(NomeUpload,"") if i<>0 then NomeFile = mid(NomeUpload, i + 1) else NomeFile = NomeUpload end if
e se il risultato delle operazioni ci fornisce un file allora viene scritto nella cartella del server:
if NomeFile<>"" then Set FSO = CreateObject("Scripting.FileSystemObject") Upload1 = True DimensioneFile1 = len(ContenutoFile) EstensioneFile1 = right(ContenutoFile,3) NomeFile1 = NomeFile Set textStream = FSO.CreateTextFile(server.mappath(NomeFile1), True, False) textStream.Write ContenutoFile textStream.Close Set textStream = Nothing Set FSO = Nothing end if end if
Lo stesso discorso vale anche per i campi dei file : nel caso in cui fossero presenti più campi file basta duplicare la condizione cambiando unicamente il nome del campo e delle variabili. Es.
if instr(Intestazione,"file2") > 0 then i = InStr(Intestazione,"filename=") j = InStr(i + 10,Intestazione,chr(34)) NomeUpload = Mid(Intestazione,i + 10,j-i-10) i = InStrRev(NomeUpload,"") if i<>0 then NomeFile = mid(NomeUpload,i + 1) else NomeFile = NomeUpload end if if NomeFile<>"" then Set FSO = CreateObject("Scripting.FileSystemObject") Upload2 = True DimensioneFile2 = len(ContenutoFile) EstensioneFile2 = right(ContenutoFile,3) NomeFile2 = NomeFile Set textStream = FSO.CreateTextFile(server.mappath(NomeFile2), True, False) textStream.Write ContenutoFile textStream.Close Set textStream = Nothing Set FSO = Nothing end if end if
A questo punto il file è stato ricevuto dal server e scritto quindi le operazioni di upload sono terminate.
Gli altri campi possono essere utilizzati a seconda di quello che serve, o per uploadare un altro file (se sono campi file), per inserire dei dati all'interno di database (se sono campi testo, dropdown, checkbox, ....), per spedire mail, oppure per qualsiasi altra necessità.