// 프로젝트명: ISAPI,CGI 파일 업로드 모듈
// 글쓴이: 송 인 표(songinpyo@yahoo.co.kr)
// 일자: 2000.7.12
//
// 제가 그동안 이곳에서 받은 고마움으로 아래의 자료를 정리해서 올립니다.
// 단, 약간의 인터넷관련 프로그래밍을 해보신분 위주로 주석을 달아놓으니 참고하시기 바랍니다.
// 물론 저두 이곳의 팁모아에 있는 김경수님의 자료를 배경으로 재구성한것입니다.
// 그분께 감사드립니다.
// 아래의 소스는 현재 사용중인 게시판의 소스를 변형없이 그대로 올린것이니 성능상에는
// 문제가 없으나 좀 지저분할 수 있습니다.
// 이점 양해바라며 더이상 업로드에 대해 물으시는 분이 없으셨으면 합니다.
/*
먼저 게시판 CGI의 구조는 다음과 같아야 합니다.
** 글쓰기 입력폼 의 구성
업로드 파일을 얻는 부분을 으로 한다는 것만
알고 넘어갑니다.(이름은 pAttachFile임)
여기서 [Action명]은 글을 등록시키는 Action의 URL이라고 보면됩니다.
ex> /mbbs/mbbs.dll/new?bbs=test1
*/
위와같이 글입력 부분을 구성했다면 다음은 글입력시 폼의 내용을 받아 실제로 DB에 저장하는 부분인데요
기존에 작성해 둔것이 있다면 과감히 지우시기 바랍니다.
전혀 섞어서 쓸 수 없습니다.
왜냐면 파일을 업로드하지 않는다면 그대로 써도 무방하나 파일을 올린다면 파일이 인터넷상에 전송되어
일정한 형식으로 날아오므로 파일과 사용자의 입력들을 수동으로 쪼개는 작업(파싱)을 해 주어야 합니다.
델파이에선 사용자의 입력만 쪼개주더군요...왜일까.....음...
그러니 기존의 모듈은 과감히 지우는게 낮겠죠...
//제 프로그램에서 Post란 액션명으로 작업하였습니다.
procedure TWebModule1.WebModule1PostAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
//실제 안쓰이는 변수가 있을 수 있으나 참고하시라고 그대로 올립니다.
var
iViewCount: integer;
sBBS,sWriter,sTitle,sContent,sPassword,sEMail,sType:String;
bNoError:Boolean;
dtCreated:TDateTime;
sTemp:string;
sClassStr:string;
sClassID:string;
imNo,irNo:integer;
sMode,sNo:string;
iMode,i,j:integer;
bPassOK,bPassAdminMaster:boolean;
sPass1,sPass2:string;
sTemp1,sTemp2:string;
sSendHTML:string;
qList,qInfo,qCla:TQuery;
MasterOK,AdminOK,ManagerPassOK:boolean;
sSerial:string;
sPassMaster,sPassAdmin:string;
sUserHome:string;
strSaveAs, strSaveFrom, strSep, strReceived, strAdd: String ;
strSaveExt:string;
iTmp, iTotal: integer ;
F: File of char ;
Ticks: dword ;
s,s1:string;
si:integer;
vWriter:string;
vEmail,vTitle,vPassword:string;
vCla,vContent,vType:string;
bFileAdd,b1,bx:boolean;
dbFile:string;
vRecTempValue:Integer;
vRecValue:string;
vRecCount:integer;
vClaID:string;
vClass:string;
sUpFileError:string;
tblMaster:TQuery;
begin
sUpFileError:='';
// 전체컨텐츠(사용자의입력+파일)의 길이를 얻어온다.
iTotal := Request.ContentLength ;
// 실제컨텐츠를 받아온다.
strReceived := Request.Content ;
// 현재의 시간을 틱 단위로 받아온다.
// 이 부분은 자료를 인터넷상에서 실시간으로 받다 끊기는 불상사에 대비해
// 시작 시간을 기록해두는것임
Ticks := GetTickCount;
// 현재받은 컨텐츠의 길이가 전체 컨텐츠보다 작으면
if Length (strReceived) < iTotal then begin
repeat
//strAdd에 현재 받은 컨텐츠 양인 iTotal에서 새로 받아온 컨텐츠의 양을
//뺀값만큼 다시 자료요구
strAdd := Request.ReadString (iTotal - Length(strReceived)) ;
//새로받은 컨텐츠의 길이 저장
iTmp := Length (strAdd) ;
//길이가 0보다 크면 (받은게 있으면)
if iTmp > 0 then
begin
// 시간을 다시 받아온다.
ticks := GetTickCount ;
// 전체 받은 컨텐츠에 새로받은 컨텐츠 첨가
strReceived := strReceived + strAdd ;
end ;
// 반복을 언제까지 하냐면
// 전체받은 컨텐츠의 양이 iTotal 보다 크거나 같으면
// 또는 3초이상 받기가 진행되지 않을 경우
until (Length (strReceived) >= iTotal) or ((GetTickCount - Ticks) > 10000) ;
end;
/*
아래의 소스를 보면 #13#10 즉 캐리지리턴값을 많이 거론합니다.
왜냐면 인터넷상에서 옮겨다니는 자료가 #13#10을 분리하는 잣대로 사용하기 때문이죠
*/
// 첫번째 케리지 리턴키를 찾는다.
iTmp := pos (#13#10, strReceived) ;
// 1보다 작거나 같으면 아래의 에러 전송
// 첫번째 캐리지 리턴이 없으면 파일형태가 잘못 전송된것임
if iTmp <= 1 then
raise Exception.Create ('파일형태전송안됨') ;
// strReceived 를 첫번째 문자부터 케리지리턴 이전문자 까지 strSep에 저장
StrSep := Copy (strReceived,1, iTmp - 1) ;
// 삭제한다 strReceived 문자열의 캐리지리턴(#13#10) 까지 삭제
delete (strReceived, 1, iTmp + 1) ;
/*
아래의 부분은 사용자의 입력들을 받아오는 부분입니다.
경호님의 소스엔 업는 부분들이죠...
vWriter는 writer라는 이름의 입력필드를..
vEmail은 email라는 이름의 입력필드의 값을 가져옵니다.
그런데 말이죠 GetFormField라는 함수는 제가 만든것입니다.
맨아래 부분에 붙혀 두었으니 참고바랍니다.
*/
sBBS:=GetFormField(strReceived,'bbs',FALSE);
vWriter:=GetFormField(strReceived,'writer',FALSE);
vEmail:=GetFormField(strReceived,'email',FALSE);
vTitle:=GetFormField(strReceived,'title',FALSE);
vPassword:=GetFormField(strReceived,'password',FALSE);
vCla:=GetFormField(strReceived,'ClaID',FALSE);
vType:=GetFormField(strReceived,'OnHTML',FALSE);
//여기서 중요한것하나 content필드는 마지막 함수인자가 TRUE이죠...
//왜일까요
//왜냐면 메모필드의 줄바꿈도 캐리지리턴을 사용하므로 메모필드에 대한
//입력은 GetFormField에서 따로 해주기 때문이죠...
vContent:=GetFormField(strReceived,'content',TRUE);
//파일이 올바르게 저장될