找回密码
 会员注册
查看: 118|回复: 0

【ASP】文件上传

[复制链接]

250

主题

1

回帖

819

积分

管理员

积分
819
发表于 2024-2-29 08:34:00 | 显示全部楼层 |阅读模式

由于VBScript这门古老的编程语言并没有像ASP.NET,Servlet、Struts2,PHP等封装好文件上传的方法,绝对不可能一个request.form["file"]就能够拿到文件,因此处理文件上传是很艰难的,需要自己截获HTTP传递过来的二进制报文,进行报文中的二进制字符切割,才能拿到文件以及我们想要的信息,不过这也更接近底层,更能让我们清楚HTTP文件上传的原理。

网上一些文章的VBScript的文件上传写得天华龙凤,短短的3KB代码居然能写到16KB,让人完全看不懂在干什么。或者就是用a,b,c命名,完全不知道怎么修改。而且大多数流传下来的文章都没有考虑到如果此网站是UTF-8编码的问题,容易造成乱码,毕竟文件上传涉及二进制操作,不是一句简简单单的Response.Charset="UTF-8"然后加个<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>就能完成的事,还需要对二进制文件流的编码进行修改。甚至还有些是用AspUpload来做,你不可能保证任何一个服务器都有这个组件吧?这会严重影响迁移问题。

下面,将为大家剖析如何在ASP做文件上传,让大家也写出属于自己的文件上传类!

将完成,如下图的一个文件系统:


不仅能够完成文件上传,还能自定义服务器保存文件的文件名,比如这里以原文件名+时间戳的方式保存文件,获取用户上传的后缀(你可以据此进一步加工,限定用户上传的文件类型了)等。

具体制作过程如下:

1、首先是这个工程的目录结构:


在进行代码写作之前,请保证你网站,至少是upload_file文件夹的Web共享是打开的,在属性界面有如下图的属性:


同时,Internet来宾账户有读取、写入的权限。


不然,有可能出现二进制流无法写入文件的情况,然而VBScript这门古老的编程语言是不会报错的,每次处理二进制流出现问题,它就给你看一个完全空白页面,就只会沉默,不跟你沟通,很蛋疼的。

2、之后是upload.html这个上传表单,本来没什么好说的,主要是表单有两个小地方需要注意的,这个表单必须给file标好name,同时表示这个表单是扔二进制数据上去upload.asp,同时必须用post的方式,而不是简简单单的文件。

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>文件上传</title>
  6. </head>
  7. <body>
  8. <form method="post" action="upload.asp" enctype="multipart/form-data"><!--一定要有enctype="multipart/form-data",表示这个表单是传递二进制数据的,同时不能再传一些text,password这些无关的文件域上去了。-->
  9. <input type="file" name="file"/><!--这里的file文件域,就是一定要有name属性,虽然在之后的二进制处理根本没有用到这个name,你随便给个名称都行,但就是要有-->
  10. <input type="submit" value="提交" />
  11. </form>
  12. </body>
  13. </html>
复制代码

如果这个file域没有name属性的话,无论你上传什么东西,upload.asp接受到的二进制流就只能是如下的东西,换句话说,是无法接受文件的。


3、最后就是这个工程的精华,upload.asp。

首先,你完全可以在upload.asp写入如下的代码:

  1. <%
  2. filesize=Request.TotalBytes
  3. filedata=Request.BinaryRead(Request.TotalBytes)
  4. response.BinaryWrite(filedata)
  5. %>
复制代码

将接受到的二进制数据打印出来,比如你将C盘的一个内容如下的aa.txt文件在upload.html的表单提交给upload.asp的话:


上述的代码,在upload.asp打印出来的东西如下:


接下来,你的目标很明了,就是对这串二进制字符进行切割,这串二进制内容里面有我们想要的一切信息,包括文件内容、客户端上传的文件名,

里面的-----------------7e010b37206c4其实是条分割线来的,如果你的表单里面有多个带name的文件域,则你会发现系统会用-----------------7e010b37206c4将多个文件报文分割。

同时,这里有部分回车在IE6浏览器中显示不出来,你可以用查看源代码的方式,看得一清二楚。

upload.asp具体代码如下所示:

  1. <%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
  2. <%
  3. '禁止缓存'
  4. Response.CacheControl="no-cache"
  5. Response.Expires=-1
  6. Response.Charset="UTF-8" '配合第一行设定网页编码
  7. if Request.TotalBytes then '如果上传文件非空'
  8. set read_stream=createobject("adodb.stream") '设置一个流'
  9. read_stream.Type=1 '这个流读二进制数据,如果Type=2则读文本数据'
  10. read_stream.Open '打开流'
  11. read_stream.write Request.BinaryRead(Request.TotalBytes) '将表单传过来的二进制数据写入流read_stream'
  12. '将流read_stream的所有数据读到binary_stream中,binary_stream相当于一个临时变量,接下来将对binary_stream进行切割,以免污染read_stream中的原数据'
  13. read_stream.Position=0
  14. binary_stream=read_stream.Read
  15. enter=chrB(13)&chrB(10) '二进制流中的回车'
  16. first_enter=clng(instrb(binary_stream,enter)) '寻找第一个回车的位置'
  17. second_enter=instrb(first_enter+1,binary_stream,enter) '寻找第二个回车的位置'
  18. set write_stream=createobject("adodb.stream") '定义一个流write_stream'
  19. write_stream.type=1 'write_stream是处理二进制数据的'
  20. write_stream.open
  21. '将read_stream中文件信息部分写到write_stream'
  22. read_stream.Position=first_enter+1
  23. read_stream.copyto write_stream,second_enter-first_enter-3
  24. write_stream.Position=0
  25. write_stream.type=2 '再将write_stream转为文本流'
  26. write_stream.CharSet="UTF-8"
  27. file_info=write_stream.readtext '写到file_info这个字符串'
  28. write_stream.Close '暂且关闭write_stream这个流,接下来对file_info这个字符串进行切割'
  29. file_name=mid(file_info,instrRev(file_info,"")+1) '取得全文件名'
  30. file_pre_suffix=left(file_name,instrRev(file_name,".")-1) '取得文件前缀'
  31. suffix=mid(file_name,instrRev(file_name,".")) '取得文件后缀,带.的'
  32. server_file_name=file_pre_suffix&"_"&datediff("s","1970-01-01 00:00:00",now)&suffix '在服务器保存的文件名就是“原文件前缀_时间戳.原文件后缀名”'
  33. delimiter=leftB(binary_stream,clng(instrb(binary_stream,enter))-1) '取得-----------------7e010b37206c4这个文件分隔符,用于给字符串处理函数找到文件内容'
  34. third_enter=instrb(second_enter+1,binary_stream,enter) '找第三个回车的位置'
  35. file_begin_position=clng(instrb(third_enter+1,binary_stream,enter))+1 '获取文件内容第一个字符之前的位置'
  36. file_end_position=clng(instrb(lenb(delimiter),binary_stream,delimiter))-3 '获取文件内容中最后一个字符的位置,就是第二个分隔符"delimiter"开始的前一个二进制字符'
  37. write_stream.type=1 'write_stream是处理二进制数据'
  38. write_stream.open
  39. read_stream.Position=file_begin_position '将流read_stream的开始位置移到文件开始的位置'
  40. read_stream.copyto write_stream,file_end_position-file_begin_position '把流read_stream的开始位置之后 长为 文件长度 的内容复制到write_stream,其中文件长度就是文件结束的位置file_end_position-文件开始的位置file_begin_position'
  41. write_stream.SaveToFile server.mappath("upload_file/"&server_file_name),2 '将write_stream转化为文件,保存在设定好的文件目录'
  42. '人走带门,关闭所有用到的流'
  43. write_stream.Close
  44. Set write_stream=nothing
  45. read_stream.Close
  46. Set read_stream=nothing
  47. '打印文件信息到网页'
  48. response.write "你上传的文件是:"&file_name&"<br>"
  49. response.write "你上传文件的后缀为:"&suffix&"<br>"
  50. url="http://"&Request.ServerVariables("HTTP_HOST")&"/my_asp/upload/upload_file/"&server_file_name
  51. response.write "访问地址:<a href='"&url&"' target='_blank'>"&url&"</a><br>"
  52. response.write "<a href='upload.html'>返回</a><br>"
  53. end if
  54. %>
复制代码

上述代码做的事,如下图所示:


说白了就是一个字符串切割的过程,虽然这个字符串切割过程有点复杂。

利用instr函数来确定字符在字符串位置,InStr(string1,string2)返回的是string2在string1出现的位置。例如:

  1. SearchString="XXpXXpXXPXXP"'被搜索的字符串。
  2. SearchChar="P"'要查找字符串"P"。
  3. MyPos=Instr(SearchString,SearchChar)'返回9。
复制代码

而Clng则是强行讲其转化为long型。

至于LEFT函数用于从一个文本字符串的第一个字符开始返回指定个数的字符,例如:

  1. AnyString = "Hello World" '定义字符串。
  2. MyStr = Left(AnyString, 1) '返回 "H"。
  3. MyStr = Left(AnyString, 7) '返回 "Hello W"。
  4. MyStr = Left(AnyString, 10) '返回 "Hello Worl"。
复制代码

而Mid函数用法如下:

Mid(String As Variant, Start As Long, [Length As Variant]) As Variant

String,必选。变体(字符串)表达式,要被截取的字符。如果该参数为Null,则函数返回Null。

Start,必选。数值表达式,从左起第几位开始截取。

Length,可选,从Start参数指定的位置开始,要向右截取的长度。如果省略,将指定为从Start参数位置开始向右到字符串结尾的所有字符数。

例子如下:

  1. v=Mid("VisualBasic",0,12)'提示实时错误5
  2. v=Mid("VisualBasic",1,6)'v的值为"Visual"
  3. v=Mid("VisualBasic",1,20)'v的值为"VisualBasic"
  4. v=Mid("VisualBasic",8)'v的值为"asic"
  5. v=Mid("VisualBasic",15)'v的值为空字符串
  6. v=Mid("中文VB",2,2)'v的值为"文V"
复制代码

当然还有right函数,不过left与带参数与不参数的mid函数足矣。

其实这些函数都是从Excel里面来的。唯一需要注意的是,在VBScript需要严格区分二进制的流的截取和字符串的截取,截取二进制里面的东西函数后面都补一个b,例如找二进制中字符出现的位置用instrb而不是原版的instr,instr是用来处理文本、字符串的。

form表单传递过来的一个二进制流,而部分二进制流的文本信息部分被转化为字符串来保存,这需要区别对待的。


通过,上述的例子,你就可以在ASP中实现文件上传了,配合《【ASP】利用MVC分层结构,优化ASP的登录系统的写作》(点击打开链接),你可以利用Access2003+记事本+IIS服务器,写出一个需求不大但严格要求不能在服务器乱装东西的小网站。这也是当年XP刚刚出来的时候,辉煌一时的建站方式。当然,现在的Windows2003一般都在跑SQL Server+ASP.NET了,不过研究一下前辈的东西有好处的。


来源:https://blog.csdn.net/yongh701/article/details/50549086
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?会员注册

×
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 13:14 , Processed in 0.688416 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表