程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 用DELPHI為ASP開發文件上載組件

用DELPHI為ASP開發文件上載組件

編輯:Delphi
ASP(Active Server Page)是微軟公司的產品,由於它編程很容易上手,能快速開發功能強大的動態網站,現在很多網站(特別是Intranet/Extranet內部網)采用了NT+IIS+ASP的模式,使得ASP成為目前較為流行的網站開發腳本語言。在WEB服務中,文件上載服務是一個很常見的功能,而WIN9X下的PWS沒有提供相關組件;NT下的IIS提供了一個Post Acceptor組件,但由於它要檢查用戶的WWW訪問權限而變得不太好用;也可以從Internet上下載有關組件,但這些大多都是商業組件,用於下載的是試用版,在使用時間或功能上都有限制。由於ASP可以調用標准的OLE/COM組件,我們可以用VB/VC/DELPHI等高級編程工具根據我們自己的要求來定制自己的ASP文件上載組件,滿足自己的應用系統要求。
  
  下面將討論用DELPHI為ASP開發文件上載組件的原理和具體實現過程。
  
  
  一、文件上載的實現原理
  
  基於Web方式數據上傳,要遵從RFC1867標准,上載的文件數據也不例外。如用下面HTML頁面文件(Delphiup.htm)選擇上載文件:
  
  <!-- DelphiUp.htm:文件上載界面 -->
  
  <Html><head><title>文件上載</title></head><body>
  
  用DELPHI編寫的文件上載組件實現文件上載
  
  <form NAME="UploadForm" ACTION="Delphiup.ASP" METHOD="POST" ENCTYPE="multipart/form-data">
  
  <p>文件另存為:<input TYPE=text NAME="SaveAs">
  
  <p>請要選擇上載的文件:<input TYPE=file NAME="FileData">
  
  <input type="submit" name="b1" value="確認上載"> </p>
  
  </form>
  
  </body></Html>
  
  當客戶端選擇了一個文件(如Test.TXT,其內容為“這裡是一個用於上載的文件的內容。”)並按
  
  “確認上載”按鈕提交數據後,服務器端程序收到的數據將具有如下形式:
  
  -----------------------------7cf1d6c47c#13#10
  
  Content-Disposition: form-data; name="SaveAs"#13#10#13#10
  
  NewFileName#13#10
  
  -----------------------------7cf1d6c47c#13#10
  
  Content-Disposition: form-data; name="FileData"; filename="D: est.txt"
  
  Content-Type: text/plain#13#10#13#10
  
  這裡是一個用於上載的文件的內容。#13#10
  
  -----------------------------7cf1d6c47c#13#10
  
  Content-Disposition: form-data; name="b1"#13#10#13#10
  
  確認上載#13#10
  
  -----------------------------7cf1d6c47c--
  
  其中,“-----------------------------7cf1d6c47c”是分界符,用於分隔表單(Form)中的各個域;
  
  #13#10是回車換行符的DELPHI表示。我們可以這樣認為,每個表單域的信息描述,都是以分界符加一對回車換行符#13#10開始;表單域名以“name="”開始,以“"”為結束;表單域值以兩對回車換行符#13#10#13#10開始,以一對回車換行符#13#10#加分界符結束;文件名稱以“filename="”開始,以“"”為結束。有了這些標志,我們就可以獲取表單域的名稱和值以及要上載的文件的名稱,從而實現文件數據的讀取和存儲了。
  
  
  二、文件上載的實現過程
  
  在理解上面提到的數據格式後,自己動手編寫一個文件上載組件對我們來說已經不是困難了。
  
  
  (一)開始建立一個ASP組件的工程
  
  如果您對用DELPHI開發OLE Automation Server的步驟不太熟悉的話,請參見《電子與電腦》1999年第06期的一篇文章《用DELPHI開發用於ASP的OLE Automation Server 》。
  
  這裡只簡要介紹一下操作步驟。
  
  1、建立ActiveX Library工程
  
  在DELPHI中選擇菜單File=》New...,在“New Item”對話框的ActiveX選項卡中選擇“ActiveX Library”,DELPHI會自動創建一個DLL工程Project1。
  
  2、建立Automation組件
  
  在DELPHI中選擇菜單File=》New...,在“New Item”對話框的ActiveX選項卡中選擇“Automation Object”;然後在“Automation Object Wizard”對話框中輸入Class Name(如“UploadFile”),Instancing選擇“Multiple Instance”即可,單擊“OK”後DELPHI會自動創建一個TLB(Type Library)文件Project1_TLB.PAS和一個PAS(Unit)文件Unit1.PAS。在Type Library設計窗口中,將Project1改名為MyUpload,則該文件上載組件的OLE注冊碼為“MyUpload.UploadFile”。
  
  3、引入ASP類型庫
  
  為了使用ASP的五個內建對象(Request、Response、Server、Application、Session),需要引入ASP類型庫。我們主要利用Request對象讀取從客戶端傳遞到服務器端的數據。
  
  在Project菜單中選擇“Import Type Library”,在“Import Type Library”對話框的“Type LibrarIEs”列表選擇“Microsoft Active Server Pages Object Library(Version 2.0)”(如果沒有這個選項,請確定您的計算機上安裝了IIS3以上或PWS4以上並且ASP.DLL已正確注冊),DELPHI會自動創建一個TLB文件ASPTypeLibrary_TLB.PAS,其中有我們需要的ASP對象類型聲明。
  
  4、定義OnStartPage、OnEndPage過程
  
  當在ASP頁面上用Server.CreateObject創建一個OLE對象實例時,WEB服務器會調用其方法OnStartPage,將ASP應用環境信息傳遞給該對象,我們可以在該過程中獲取客戶端信息;當在ASP頁面中釋放一個OLE對象實例時,WEB服務器會調用其方法OnEndPage,我們可以在該過程中進行釋放內存等結束操作。在我們這個組件中,我們要用到其OnStartPage方法。
  
  OnStartPage方法應該在Unit1.PAS中定義,OnStartPage的函數原型為:
  
  procedure OnStartPage(AScriptingContext: IUnknown);
  
  其中參數AScriptingContext是一個IScriptingContext類型變量,包含五個屬性(Request、Response、Server、Application、Session)分別對應ASP的五個內建同名對象。
  
  我們需要在TLB定義窗口(VIEw=》Type Library)中,為IUploadFile增加方法OnStartPage,其Declaration語句為“procedure OnStartPage(AScriptingContext: IUnknown);”。
  
  
  (二)提取客戶端上傳的數據
  
  該工作可以放在OnStartPage過程中進行。
  
  利用AScriptingContext的屬性Request(類型為IRequest)中的屬性TotalBytes(請求信息內容長度)和方法BinaryRead可將客戶端上傳的請求信息數據讀取到一個Byte類型的數組中,然後按RFC1867標准定義的數據格式來分析和提取數據。
  
  1、首先定義TUploadFile的幾個私有變量
  
  在單元文件UP01.PAS(由Unit1.PAS另存)中加入對ASPTypeLibrary_TLB.PAS的引用(Uses),
  
  然後加入
  
  private
  
  FContentLength : LongInt;//請求信息內容長度
  
  FContentData : Variant;//內容數據,以數組形式存儲請求信息內容
  
  FFileName, //要上載的文件名稱
  
  FDelimeter : string; //表單域分界符
  
  FScriptingContext : IScriptingContext;//ASP處理上下文環境內容
  
  FFileDataStart, //文件數據開始位置
  
  FFileDataEnd : LongInt; //文件數據結束位置
  
  
  2、提取客戶端上傳的請求信息數據
  
  //在OnStartPage事件中,獲取ASP上下文信息、請求信息內容、表單域的分界符、文件數據
  
  procedure TUploadFile.OnStartPage(AScriptingContext: IUnknown);
  
  var
  
  ARequest : IRequest; //WWW請求對象
  
  AOleVariant : OleVariant; //記錄請求信息內容長度
  
  intDelimterLength : integer;//分界符長度
  
  longIndex,ALongInt,longPos : LongInt;
  
  ContentData : AnsiString;//請求信息內容的字符串表示
  
  strTemp : string;
  
  FindEndOfFileData : boolean;//是否找到文件數據結束位置
  
  begin
  
  //提取客戶端上傳的請求信息數據
  
  FScriptingContext := AScriptingContext as IScriptingContext;//獲取ASP上下文信息
  
  ARequest := FScriptingContext.Request;//獲取WWW請求信息
  
  FContentLength := ARequest.TotalBytes;//請求信息內容長度
  
  //創建動態數組,用於以數組形式存儲請求信息內容
  
  FContentData := VarArrayCreate( [0,FContentLength], varByte );
  
  //將請求信息內容存儲到數組中
  
  AOleVariant := FContentLength;
  
  FContentData := ARequest.BinaryRead( AOleVariant );//讀取請求信息內容
  
  //將請求信息內容轉化為字符串,便於定位
  
  ContentData := ';
  
  for longIndex := 0 to FContentLength - 1 do
  
  begin
  
  ContentData := ContentData + chr( Byte( FContentData[ longIndex ] ));
  
  if FContentData[ longIndex ] = 0 then break;//0表示內容結束
  
  end;
  
  
  3、獲取分界符、上載文件名稱
  
  //獲取表單域的分界符
  
  longPos := pos( #13#10,ContentData );//回車換行符所在位置
  
  FDelimeter := Copy( ContentData,1,longPos-1);//該位置之前的內容為分隔符
  
  
  //獲取帶源路徑的文件名稱,在請求信息內容中,文件名稱以
  
  //filename="path/filename"的形式存儲
  
  strTemp := 'filename="';//文件名稱在“filename="”之後
  
  longPos := pos( strTemp, ContentData );//獲取“filename="”位置
  
  if longPos <= 0 then
  
  begin
  
  FFileName := ';
  
  FFileDataStart := -1;
  
  FFileDataEnd := -2;
  
  exit;
  
  end;
  
  //獲取下個雙引號“"”之前的內容,即帶源路徑的文件名稱
  
  longPos := longPos + length( strTemp );
  
  strTemp := ';
  
  for longIndex := longPos to FContentLength - 1 do
  
  if ContentData[ longIndex ] <> '"' then
  
  strTemp := strTemp + ContentData[ longIndex ]
  
  else break;
  
  FFileName := strTemp;
  
  
  4、獲取文件數據的在請求信息內容中的開始、結束位置
  
  //文件數據開始位置在文件名稱後的第一個#13#10#13#10之後
  
  delete( ContentData, 1, longIndex );
  
  strTemp := #13#10#13#10;
  
  FFileDataStart := longIndex + pos(strTemp, ContentData) + length(strTemp) - 1;
  
  
  //文件數據結束位置在下一個#13#10和分界符之前
  
  //由於文件數據可能包含非法字符,不能再用字符串定位函數POS
  
  //查找下一個分界符的位置
  
  FFileDataEnd := FFileDataStart;
  
  intDelimterLength := length( FDelimeter );
  
  FindEndOfFileData := false;
  
  while FFileDataEnd <= FContentLength - intDelimterLength do
  
  begin
  
  FindEndOfFileData := true;
  
  for ALongInt := 0 to intDelimterLength - 1 do
  
  if Byte( FDelimeter[ ALongInt + 1 ] ) <>
  
  FContentData[ FFileDataEnd + ALongInt ] then
  
  begin
  
  FindEndOfFileData := false;
  
  break;
  
  end;
  
  if FindEndOfFileData then break;
  
  FFileDataEnd := FFileDataEnd + 1;
  
  end;
  
  if not FindEndOfFileData then FFileDataEnd := FFileDataStart - 1//未找到分界符
  
  else FFileDataEnd := FFileDataEnd - 3;//分界符,向前跳過#13#10
  
  end;
  
  
  (三)向ASP程序傳遞信息
  
  在進行了(二)的操作之後,我們的上載組件可以根據ASP程序的要求向其傳遞數據了。目前可以提供的數據有:客戶端源文件名稱(FFileName,含路徑)、文件大小(FFileDataEnd-FFileDataStart+1)。
  
  首先應該在TLB設計窗口中聲明如下兩個方法GetFileName和GetFileSize。
  
  1、返回客戶端源文件名稱(含路徑)
  
  //返回客戶端源文件名稱(含路徑)
  
  function TUploadFile.GetFileName: OleVariant;
  
  begin
  
  result := FFileName;//客戶端源文件名稱(含路徑)
  
  end;
  
  2、返回文件大小
  
  //返回文件大小(Bytes)
  
  function TUploadFile.GetFileSize: OleVariant;
  
  begin
  
  result := FFileDataEnd - FFileDataStart + 1;
  
  end;
  
  
  (四)保存文件
  
  在進行了(二)的操作之後,我們的上載組件可以根據ASP程序的要求保存文件了。首先應該在
  
  TLB設計窗口中聲明如下兩個方法SaveFileAs和SaveFile。
  
  1、按指定文件名稱保存文件
  
  //按指定的文件名稱保存文件,參數FileName為指定的文件名稱,返回值True表示文件保存成功
  
  function TUploadFile.SaveFileAs(FileName: OleVariant): OleVariant;
  
  var
  
  longIndex : LongInt;
  
  AFile : file of byte;//以二進制的形式保存文件
  
  byteData : Byte;
  
  begin
  
  result := true;
  
  try
  
  assign( AFile, FileName );
  
  rewrite( AFile );
  
  for longIndex := FFileDataStart to FFileDataEnd do
  
  begin
  
  byteData := Byte( FContentData[ longIndex ] );
  
  Write( AFile, byteData );
  
  end;
  
  CloseFile( AFile );
  
  except
  
  result := false;
  
  end;
  
  end;
  
  2、按缺省文件名稱保存文件
  
  //按缺省文件名稱保存文件,將文件以同名文件保存在調用頁面所在目錄
  
  function TUploadFile.SaveFile: OleVariant;
  
  var
  
  CurrentFilePath : string;
  
  begin
  
  //獲取調用頁面所在目錄
  
  CurrentFilePath := FScriptingContext.Request.ServerVariables['PATH_TRANSLATED'];
  
  CurrentFilePath := ExtractFilePath( CurrentFilePath );
  
  //保存文件
  
  result := SaveFileAs( CurrentFilePath + ExtractFileName( FFileName ));
  
  end;
  
  
  三、上載組件應用舉例
  
  在我們的例子中,DelphiUp.HTM是文件上載界面,DelphiUp.ASP用來執行文件上載操作。
  
  DelphiUp.ASP的代碼如下:
  
  <!--DelphiUp.ASP:文件上載處理頁面-->
  
  <Html><head><title>文件上載</title></head><body>
  
  <% dim Upload, FileName
  
  set Upload = Server.CreateObject("MyUpload.UploadFile")
  
  FileName = Upload.GetFileName
  
  Response.Write "<br>正在保存文件《"&FileName&"》......"
  
  if Upload.SaveFile then
  
  Response.Write "<br>文件《"&FileName&"》上載成功。"
  
  Response.Write "<br>文件大小為"&Upload.GetFileSize&"字節。"
  
  else
  
  Response.Write "<br>文件《"&FileName&"》上載失敗。"
  
  end if
  
  set Upload=nothing %>
  
  </body></Html>
  
  
  四、幾點說明
  
  1、由DELPHI自動生成的源代碼編譯的DLL文件大小有215K,可以在
  
  ASPTypeLibrary_TLB.PAS的Interface段中將Uses中的單元除ActiveX外全部刪除,在
  
  MyUpload_TLB.PAS中刪除Uses中所有單元,則生成的DLL文件大小可減少到61K。
  
  2、以上方法同樣適用於CGI程序,不過要用TWebRequest對象。
  
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved