当前位置:编程学习 > Delphi >>

用Delphi6开发ASP上传组件详解

用Delphi 6开发ASP上传组件详解
左轻侯
2002.6.20

  文件上传是WEB开发中经常要用到的功能,但ASP本身和内置的组件都不支持文件上传功能。网上流
传的一些第三方组件虽然能够解决这个问题,但大多是要收费的,更别说Open Source了。本文将详细
剖析WEB文件上传的原理,以及一步步指导读者如何用Delphi6开发一个ASP上传组件。

源码和demo我已经发布在个人主页上
http://www.wushuang.net

1 Html文件分析
  首先我们来看一个html文件源码,文件名是test.htm,功能是提供用户上传的界面:

<html>
<body>
<center>
   <form name="mainForm" enctype="multipart/form-data"
action="test.asp" method=post>
    <input type=file name=mefile><br>
     <input type=hidden name=a1 value="fdsaf">
     <input type=hidden name=a2 value="fdsaf">
     <input type=hidden name=a3 value="fdsaf">
     <input type=hidden name=a4 value="fsdfsdsaf">
     <input type=hidden name=a5 value="这个是这个">
     <input type=text name=a6 value="fdsaf">
   <input type=submit name=ok value="OK">
   </form>
</center>
</body>
</html>

  这个文件里包含了一个名为mainForm的form,以及随手写的一些input域。注意这个form和一
般的form有两个不同的地方:一是它有一个type=file的域,没有value。用浏览器打开这个文件时,
这个域会表现为一个右侧有“浏览”字样的文件输入框,用户可以通过它来选择本地硬盘上的文件。二是
form有一个特殊的属性:enctype="multipart/form-data"。这个属性告诉浏览器要上传二进制文
件,并进行相应编码。
  这种编码会产生什么样的表单信息呢?让我们来看看test.asp,也就是接受表单的asp文件的源码,
它非常简单:

<%
formsize=request.totalbytes   获得表单原始信息的长度
formdata=request.binaryread(formsize)   读取表单原始信息

response.binarywrite formdata  返回表单原始信息
%>

  如读者在注释中了解的,这段代码的功能是将表单的原始信息返回。让我们来看看它的运行效果。将
这两个文件置于web目录下,访问test.htm。在文件输入框中,选择一个文件(我选了一个jpg图片,
不过最大不要太大)。提交,然后可以看到这样一堆乱七八糟的信息:

-----------------------------7d2227629012e Content-Disposition: form-data;
name="mefile"; filename="C:Documents and SettingsaaaMy DocumentsMy
Pictureszzjh.jpg" Content-Type: image/pjpeg (作者注:以下为乱码)
-----------------------------7d2227629012e Content-Disposition: form-data;
name="a1" fdsaf -----------------------------7d2227629012e Content-Disposition:
form-data; name="a2" fdsaf -----------------------------7d2227629012e
Content-Disposition: form-data; name="a3" fdsaf
-----------------------------7d2227629012e Content-Disposition: form-data;
name="a4" fsdfsdsaf -----------------------------7d2227629012e
Content-Disposition: form-data; name="a5" 这个是这个
-----------------------------7d2227629012e Content-Disposition: form-data;
name="a6" fdsaf -----------------------------7d2227629012e Content-Disposition:
form-data; name="ok" OK -----------------------------7d2227629012e--

  这就是用"multipart/form-data"方式编码的表单原始信息。其中那一段看起来是乱码的部分,就
是jpg图片的编码。
  分析一下这段信息的格式:  

-----------------------------7d2227629012e 这是各个域之间的分隔符。
Content-Disposition: form-data; 说明这是表单中的域。
name="mefile"; 域的名称。
filename="C:Documents and SettingsaaaMy DocumentsMy Pictureszzjh.jpg" 上
传文件在本地硬盘上的名称。
Content-Type: image/pjpeg 文件类型。
后面是文件本身的数据。

  其它各个域的信息也可以以此类推。
  众所周知,在ASP中,使用request对象,可以访问用户提交表单的各个域。因为request对象
会对原始的表单信息进行解析,提取出表单中每个域的值。但是,request并不能解析这
"multipart/form-data"格式的表单信息。这就是ASP不能直接支持文件上传的原因所在。读者可以
试试,在test.asp中,用request("mefile")这样的格式,是不能读取到正确的信息的。
  问题的症结已经找到,解决的思路也很简单:用Delphi开发一个COM组件,接受这种原始表单信息,
将各个域一一提取出来,返回给asp文件。也就是完成request对象没有完成的功能。

2 用Delphi开发组件

  Delphi6对开发ASP组件提供了极好的支持,大大简化了我们的开发过程。
  启动Delphi 6,选择File-New-Other-ActiveX-ActiveX Library,这样就建立了一个
ActiveX库。将此Library改名为myobj,存盘。选择File-New-Other-ActiveX-Active Server
Object,在CoClassname中填入upfile,确定。这时会跳出一个标题为myobj.tlb的对话框,这是
Delphi特有的以可视化方式编辑COM接口的功能,用Delphi开发过COM的读者应该比较熟悉。
  在myobj下的名为Iupfile的Inte易做图ce下,添加5个属性和一个方法。如果不懂得如何操作,
请参见Delphi参考书的相关部分。按F12可以看到生成的相应的myobj_tlb.pas文件,其中的
Iupfile接口应该是这个样子:

  Iupfile = inte易做图ce(IDispatch)
    [{5C40D0EB-5A22-4A1E-8808-62207AE04B51}]
    procedure OnStartPage(const AScriptingContext: IUnknown); safecall;
    procedure OnEndPage; safecall;
    function  Get_Form(Formname: OleVariant): OleVariant; safecall;
    function  Get_FileName: OleVariant; safecall;
    function  Get_FileSize: Integer; safecall;
    procedure FileSaveAs(FileName: OleVariant); safecall;
    function  Get_FileData: OleVariant; safecall;
    function  Get_FileType: OleVariant; safecall;
    property Form[Formname: OleVariant]: OleVariant read Get_Form;
    property FileName: OleVariant read Get_FileName;
    property FileSize: Integer read Get_FileSize;
    property FileData: OleVariant read Get_FileData;
    property FileType: OleVariant read Get_FileType;
  end;

  其中的OnStartPage方法和OnEndPage方法是Delphi默认生成的,其它的是手动加入的。
  切换到unit1.pas(也是Delphi自动生成的),改名为upfile.pas存盘。可以看到存在一个
Tupfile类的声明,它是继承自TASPObject类和Iupfile接口的。Delphi 6已经自动生成了相应
的代码。接下来的任务就是实现这个接口。
  除了完成Iupfile接口中的属性和方法之后,还需要补充一些东西,以便完成我们的任务。最终的
Tupfile类的声明如下:

  Tupfile = class(TASPObject, Iupfile)
  public
  protected
    procedure OnEndPage; safecall;  //页面开始
    procedure OnStartPage(const AScriptingContext: IUnknown); safecall;  //页面
结束
    procedure FileSaveAs(Filename: OleVariant); safecall;  //保存文件
    function Get_Form(Formname: OleVariant): OleVariant; safecall;  //
    function Get_FileName: OleVariant; safecall; 
    function Get_FileSize: Integer; safecall;
    function Get_FileData: OleVariant; safecall;
    function Get_FileType: OleVariant; safecall;
  private
    FContentData:string;
    FFileData,FFileName,FFileType:string;
    FFormInfo:TStringList;
    function instr(str1,str2:string;startpos:integer):integer;
    procedure AnalyFormData(content:string);
  end;

  下面我们来一一分析这些成员的具体实现。

procedure Tupfile.OnStartPage(const AScriptingContext: IUnknown);
var
  AOleVariant : OleVariant;
  tmpvar : OleVariant;
  contentlength : integer;
  i,DeliCount,pos1,pos2,lastpos : integer;
  FDelimeter : string;
begin
  inherited OnStartPage(

补充:软件开发 , Delphi ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,