1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
| <!--
Nous pouvons facilement uploader nimporte quel type de fichier sur un serveur sans avoir besoin dun quelconque composant.
Le concept est simple et se résume à trois phases :
1- Nous utilisons pour passer les données le contrôle Filename et l'enctype à multipart/form-data
2- Nous récupérons les données du fichier sous forme binaire grâce au Content-Type.
3- Nous écrivons sur le serveur les données sous le nom original du fichier.
-->
<%
' --------------------------------------------------------------
' NC-Upload V1 / UPLOAD de n'importe quel type de fichier sans composant
' Nicolas Chu
' http://www.nc-technologies.com
' (c) 1999
' --------------------------------------------------------------
Dim Contenu, TailleContenu, ContenuAscii, X, Y, Z, Position
' ---------------------------
Contenu = Request.BinaryRead(Request.TotalBytes)
TailleContenu = Request.TotalBytes
' Grâce à la méthode BinaryRead on lit la totalité du post en mode binaire que l'on place dans une variable Contenu
' La propriété TotalBytes nous Indique le nombre total des octets envoyés par le client dans le corps du message de requête.
' -------------------
ToutOk = 0
' ToutOk est une Variable Test (si tout est Ok, elle prend la valeur 1 sinon elle reste à 0
' -------------------
PosDebutFic=0
' PosDebutFic représente la position de l'octet où se trouve le début du Nom du fichier transmis
' -------------------
PosFinFic=0
' PosFinFic représente la position de l'octet où se trouve la fin du Nom du fichier transmis
' -------------------
PosDebutCont=0
' PosDebutCont représente la position de l'octet où se trouve le début du Content-Type du fichier
' -------------------
PosFinCont=0
' PosFinCont représente la position de l'octet où se trouve la fin du Content-Type du fichier
' -------------------
PosDebutFic2=0
' PosDebutFic2 représente la position de l'octet où se trouve le début du Contenu du fichier
' -------------------
PosFinFic2=0
' PosFinFic2 représente la position de l'octet où se trouve la fin du Contenu du fichier
X = 0
Y = 1
Position = 1
' -------------
' En premier lieu, on recherche la position du terme filename="
' Pour ce faire, on calcul le nombre d'octet (LimitBin) du premier élément jusqu'à filename="
' On effectue une boucle jusqu'au nombre d'octets correspondant au terme filename="
LimitASCII = "filename=" & chr(34)
LimitBin=""
for Z = 1 to Len(LimitASCII)
LimitBin = LimitBin & chrB(ASC(Mid(LimitASCII, Z, 1)))
next
' -------------------
' On recherche la position de l'octet de la chaîne Contenu jusqu'à LimitBin
' On utilise la fonction InStrB qui est disponible pour être utilisée avec les données de type octet contenues dans une chaîne.
' Au lieu de renvoyer la position du caractère de la première occurrence d'une chaîne à l'intérieur d'une autre (fonction Instrv),
' la fonction InStrB renvoie la position de l'octet.
PosDebutFic = InstrB(1, Contenu, LimitBin)
' -------------------
' On lui ajoute ensuite la longueur du terme filename=" ce qui nous permet d'avoir la position de début du nom du fichier (PosDebutFic)
if PosDebutFic <> 0 then
PosDebutFic = PosDebutFic + LenB(LimitBin)
end if
' -------------------
' On recherche la position du terme Content-Type: d'une façon similaire à notre recherche pour le terme filename="
LimitASCII = "Content-Type:"
LimitBin=""
For Z = 1 to Len(LimitASCII)
LimitBin = LimitBin & chrB(ASC(Mid(LimitASCII, Z, 1)))
next
PosDebutCont = InstrB(1, Contenu, LimitBin)
if PosDebutCont <> 0 then
' -------------------
' On trouve la position de la fin du nom du fichier (PosFinFic) à partir de la position du début du terme Content-Type:
' à laquelle on retire trois octets (un espace, une " et la première lettre du terme)
PosFinFic = PosDebutCont - 3
' -------------------
' On ajoute à PosDebutCont la longueur du terme Content-Type: , ce qui nous permet d'avoir la position de début du Content-Type (PosDebutCont)
PosDebutCont = PosDebutCont + LenB(LimitBin)
end if
' -------------------
' On en déduit le nombre de caractères composant le nom du fichier en effectuant une soustraction
NomFichier = MidB(Contenu, PosDebutFic , (PosFinFic - PosDebutFic))
' -------------------
' Nous n'avons plus qu'à traduire en texte grâce à la fonction ASCB et trouver ainsi le nom du fichier (NomFichier)
ContenuAscii = ""
for Z = 1 to LenB(NomFichier)
ContenuAscii = ContenuAscii & chr(ASCB(MidB(NomFichier, Z, 1)))
next
NomFichier = ContenuAscii
' -------------------
' On cherche la position de début du contenu du fichier en sautant les blancs
PosFinCont = InstrB(PosDebutCont, Contenu, chrB(13))
if PosFinCont <> 0 then
PosDebutFic2 = PosFinCont + 4
end if
' -------------------
' On recherche la position de fin du contenu du fichier
LimitASCII = "----"
LimitBin=""
for Z = 1 to Len(LimitASCII)
LimitBin = LimitBin & chrB(ASC(Mid(LimitASCII, Z, 1)))
next
PosFinFic2 = InstrB(PosDebutFic2, Contenu, LimitBin)
' -------------------
' Si la position de fin du contenu du fichier n'est pas 0 alors tout est OK
if PosFinFic2 <> 0 then
ToutOk = 1
end if
' -------------------
' On place le contenu binaire du fichier transmis dans la variable DataFichier
DataFichier = MidB(Contenu, PosDebutFic2 , (PosFinFic2 - PosDebutFic2))
' -------------------
' Si tout est ok, on écrit dans un fichier à la racine du serveur en plaçant d'abord dans une variable NouveauFic le chemin complet du fichier à écrire.
If ToutOk = 1 then
Position = InstrRev(NomFichier, "\")
NomFichierCourt = right(NomFichier, (Len(NomFichier) - Position))
NouveauFic = Server.MapPath("\") & "\" & NomFichierCourt
Set FileObject = Server.CreateObject("Scripting.FileSystemObject")
Set Out=FileObject.CreateTextFile(NouveauFic, True)
For I = 1 to LenB(DataFichier)
Out.Write chr(AscB(MidB(DataFichier,I,1)))
Next
Out.close
Set Out=nothing
end if
%>
----------------------------------------------
<html>
<head>
<title>Transmettre un fichier par ASP</title>
</head>
<body>
<form method="POST" action="reception.asp" enctype="multipart/form-data" target="_new">
<input type="file" name="File" size="50"><br>
<input type="submit" value="TRANSMETTRE LE FICHIER" name="Submit">
</form>
</body>
</html>
Explication:
Pour le transfert de fichier, contrairement à un formulaire "normal" dans lequel la mention enctype="..." peut être omise,
cette mention doit avoir la valeur "multipart/form-data", étant donné que dans le cas contraire, le navigateur ne reconnaît
pas qu'il doit envoyer le fichier au serveur sous la forme codée correspondante. Si cette mention est manquante ou erronée,
le formulaire sera traité tout à fait normalement, ce qui veut dire que le navigateur reçoit seulement le nom du fichier
choisi et son chemin - mais pas son contenu. De plus, on peut aussi mentionner tout de suite dans le navigateur quels types
de fichier peuvent être choisis et leur taille maximale en octets, encore que ces fonctions soient assez faciles à contourner.
C'est pourquoi dans l'exemple a été incluse côté serveur une demande de ces paramètres, qui ne se laissent pas contourner.
Sécurité
Pour exclure un usage abusif des formulaires de fichier, il a été exigé (et également respecté par les fabricants de navigateur)
qu'il ne soit pas possible d'obtenir une valeur par défaut des champs de fichier. À titre de comparaison, un champ "normal"
peut être défini avec un texte par défaut: <input type="text" name="pardefaut" size="30" maxlength="30" value="texte par défaut">.
Même contourner le problème à l'aide de JavaScript est impossible, comme par exemple définir dans un premier temps le champ
comme champ de saisie à une ligne et y indiquer un fichier par défaut, puis modifier dans un second temps le type texte en
type fichier à l'aide de l'événement onLoad, et envoyer par la suite le formulaire à l'appel de la méthode submit.
Exemple d'application
L'exemple qui suit reçoit le flux HTTP envoyé et l'exploite.
Le fichier est envoyé comme flux de données HTTP (Unicode) au serveur:
<html>
<head>
<title>Transmission de fichier par ASP</title>
</head>
<body bgcolor="white">
<%=Font%>
<%
' --- ASP FileUpload Modul GetFILE (C) 1999 by Stefan Falz
' --- activer le traitement des erreurs
' --- On Error Resume Next
' --- affectation de la cause de l'erreur qui doit être affichée quand elle se produit
Err.Source = "GetFILE HTTP-Upload"
' --- constante pour l'intitulé de l'erreur
Const ErrHeader = "<b>erreur</b><br><br>"
' --- déclarer la liste
Dim ErrArray(4)
ErrArray(0) = "10900 - Le fichier que vous envoyez est trop important."
ErrArray(1) = "10901 - erreur inconnue.<br>"
ErrArray(2) = "10902 - Aucun fichier n'a été envoyé ou transmission défectueuse. <br>"
ErrArray(3) = "10903 - Aucun fichier texte n'a été transmis.<br>"
' -- appel de la sous-routine GetFILE
Call GetFILE()
Private Sub GetFile()
' --- cette sous-routine lit le flux HTTP
' --- déclaration des variables
Dim FileText
FileText = Request.BinaryRead(Request.TotalBytes)
Dim FileTextByte
FileTextByte = ""
Dim FileTextNew
FileTextNew = ""
Dim FilePosFirst
FilePosFirst = 0
Dim FilePosLast
FilePosLast = 0
Dim FileType
FileType = ""
Dim strRevText
strRevText = ""
Dim strFileName
strFileName = ""
Dim strFileNameOnly
strFileName = ""
Dim posFileName
posFileName = 0
Dim rghFile
rghFileName = ""
Dim lenFileTextByte
lenFileTextByte = 0
' --- mention de la taille maximale + environ 500 octets pour les informations de fichier
Dim maxLength
maxLength = 25500
' --- demande de la taille du flux envoyé
If Request.TotalBytes > maxLength Then
Call Error_Handler(10900)
Exit Sub
End if
' --- recherche du code hexadécimal 0D 0A 0D 0A (début du fichier dans un flux HTTP)
FilePosFirst = InStrB(FileText, (ChrB(13) & ChrB(10) & ChrB(13) & ChrB(10)))
' --- recherche du code hexadécimal 0D 0A 2D 2D (fin du fichier dans un flux HTTP)
FilePosLast = InStrB(FileText, (ChrB(13) & ChrB(10) & ChrB(45) & ChrB(45)))
' --- recherche du code hexadécimal 2D 0A 0D à l'intérieur du flux HTTP inversé, étant donné
' --- que selon les circonstances, il peut y avoir plusieurs signes de fin de fichier.
strRevText = StrReverse(FileText)
FilePosLast = InStrB(strRevText, (ChrB(45) & ChrB(10)) & ChrB(13))
FilePosLast = LenB(FileText) - FilePosLast
' --- Interruption si la taille du fichier est 0 octet
If FilePosFirst = 0 Or FilePosLast = 0 Or FilePosLast - FilePosFirst < 5 Then
Call Error_Handler(10902)
Exit Sub
End If
' --- Interruption si la mention "Content-Disposition=text/html" manque
If InStrB(FileText, ChrB(67) & ChrB(111) & ChrB(110) & ChrB(116) & ChrB(101) & ChrB(110) & ChrB(116) & ChrB(45) & ChrB(84) & ChrB(121) & ChrB(112) & ChrB(101) & ChrB(58) & ChrB(32) & ChrB(116) & ChrB(101) & ChrB(120) & ChrB(116) & ChrB(47)) = 0 Then
Call Error_Handler(10903)
Exit Sub
End if
' --- Interruption, lorsqu'une erreur survient qui ne fait pas partie de la liste ci-dessus
If Err.Number <> 0 Then
Call Error_Handler(10901)
Exit Sub
End if
' --- Recherche du nom de fichier chemin compris dans le flux HTTP
posFileName = InStrB(FileText, ChrB(102) & ChrB(105) & ChrB(108) & ChrB(101) & ChrB(110) & ChrB(97) & ChrB(109) & ChrB(101) & ChrB(61) & ChrB(34)) + 9
rghFileText = RightB(FileText, LenB(FileText) - posFileName)
strFileName = LeftB(rghFileText, InStrB(rghFileText, ChrB(34)) - 1)
Response.Write "<strong>nom de fichier chemin compris: </strong>"
Response.BinaryWrite strFileName
Response.Write "<br>"
' --- Recherche du nom de fichier sans le chemin dans le flux HTTP
posLastSlash = InStrB(StrReverse(strFileName), ChrB(92))
strFileNameOnly = MidB(strFileName, LenB(strFileName) - posLastSlash, posLastSlash + 1)
Response.Write "<strong>le nom de fichier sans son chemin: </strong>"
Response.BinaryWrite strFileNameOnly
Response.Write "<br>"
' --- interruption si une erreur intervient
If Err <> 0 Then
Call Error_Handler(10901)
Exit Sub
End if
' --- écriture du contenu du fichier dans une liste d'octets
FileTextByte = MidB(FileText, (FilePosFirst + 4), (FilePosLast - (FilePosFirst + 4)))
' --- Recherche de la taille du fichier par la lecture de la longueur du contenu de fichier trouvé
lenFileTextByte = LenB(FileTextByte)
' --- Conversion du contenu de fichier (flux binaire) en signes Ascii
For i = 1 To lenFileTextByte
FileTextNew = FileTextNew & Chr(AscB(MidB(FileTextByte, i, 1)))
Next
' --- écriture dans un fichier du contenu du fichier trouvé.
Set objFileSys = Server.CreateObject("Scripting.FileSystemObject")
Set File = objFileSys.CreateTextFile(Server.MapPath("./") & "\" & Session.SessionID & ".tmp", True, False)
File.WriteLine CStr(FileTextNew)
File.Close
Set File = Nothing
Set objFileSys = Nothing
' --- sortie de la taille du fichier en octets
Response.Write "<strong>taille du fichier: </strong>" & lenFileTextByte & " octets.<br><br>"
' --- conversion du contenu du fichier étant donné que les pages HTML ne sont pas affichées correctement
FileTextNew = Replace(FileTextNew, "<", "<")
FileTextNew = Replace(FileTextNew, ">", ">")
FileTextNew = Replace(FileTextNew, VbCrLf, "<br>" & VbCrLf)
FileTextNew = Replace(FileTextNew, Chr(9), " ")
' --- sortie du contenu du fichier
Response.Write FileTextNew
End Sub
Private Sub Error_Handler(intErrNumber)
' --- recherche du code d'erreur transmis et sortie à l'écran
Select Case intErrNumber
Case 10900: Response.Write ErrHeader & ErrArray(0)
Case 10901: Response.Write ErrHeader & ErrArray(1)
Case 10902: Response.Write ErrHeader & ErrArray(2)
Case 10903: Response.Write ErrHeader & ErrArray(3)
Case Else: Response.Write ErrHeader & Err.Description
End Select
Exit Sub
End Sub
%>
</body>
</html> |
Partager