VFPCGI Day7

出自VFP Wiki

跳轉到: 導航, 搜尋
VFPCGI的第七天

上次還沒實做關於 POST 的部份,所以這次延續上次的例子,並且做了一些擴充,這樣可以讓你很清楚怎麼取 GET 與 POST 來的資料。

這裡我添加了一個 form,這是用來放表單資料的,再按下 submit 之後,你會在表單的下方看到讀到的結果。這邊也利用了 text...endtext 來作為一個 template 產生器,你可以看到 text...endtext 可以很方便的同時寫 html,並且在裡面嵌入變數(用<<與>>把變數括起來)。

*
* cgi05
*

SET PROCEDURE TO cgilib
DECLARE INTEGER GetStdHandle in Win32API integer nHandleType
declare integer ReadFile in Win32API integer hFile, string @ cBuffer,;
	integer nBytes, integer @ nBytes2, integer @ nBytes3

LOCAL oResponse
oResponse = CREATEOBJECT( "RESPONSE" )

LOCAL cRequestMethod, cInput
cRequestMethod = UPPER( GETENV( "REQUEST_METHOD" ) )

cInput = "<p>REQUEST_METHOD=" + cRequestMethod + "</p>"

DO CASE 
	CASE cRequestMethod == "GET"
		cInput = cInput + GETENV( "QUERY_STRING" )
	CASE cRequestMethod == "POST"
		&&lenght of input string in STDIN is in this environment variable
		LOCAL lcContentLength, lnContentLength 
		LOCAL lnHandle 
		LOCAL lcInput
		LOCAL lnOverlappedIO
		
		lcContentLength = GETENV("CONTENT_LENGTH")
		IF LEN( lcContentLength ) > 0 THEN 
			lnContentLength=VAL( lcContentLength )
		ELSE
			lnContentLength = 0
		ENDIF 

		IF lnContentLength > 0 THEN 
			&&get the input from STDIN
			lnInHandle=GetStdHandle(-10) 
			lcInPut=REPLICATE(' ', lnContentLength )
			lnOverlappedIO=0
			ReadFile(lnInHandle, @lcInPut, lnContentLength, @lnContentLength, @lnOverlappedIO)
		ELSE
			lcInput=''
		ENDIF
		cInput = cInput + lcInput
	OTHERWISE 
		cInput = ""
ENDCASE 

lcHtml = ""
TEXT TO lcHtml NOSHOW ADDITIVE TEXTMERGE 
<script language="javascript">
function method_change( form )
{
 switch ( form.cboMethod.value ) {
 case "GET": form.method = "GET"; break;
 case "POST": form.method = "POST"; break;
 }
}
</script>
<form method="get" action="vfpcgi.exe">
RequestMethod: <select name="cboMethod" onChange="return method_change(this.form);">
	<option value="GET" <<IIF(cRequestMethod=="GET", "selected", "")>> >GET</option>
	<option value="POST" <<IIF(cRequestMethod=="POST", "selected", "")>> >POST</option>
</select><br/>
<input type="text" name="txt" value=""/>
<select name="cbo">
<option value="0" selected>0</option>
<option value="1">1</option>
<option value="2">2</option>
</select><br/>
<input type="submit" value="Submit"/>
<input type="reset" value="Reset"/>
</form>
<pre>
<<cInput>>
</pre>
ENDTEXT 

oResponse.Write( lcHtml )

同時,也對上次的 Response 類別作一點修正,在上次 Response 類別裡面,用來作為 cache 的 cursor,其資料欄位是 varchar(254),換言之,每次 Write 時,只能塞入 254 個字元,如果超過的話,就完蛋了。這次我把她修正為 M,也就是 Memo 型態。

DEFINE CLASS RESPONSE as Custom 
	bDirty = .F.
	bHeaderOut = .F.
	ADD OBJECT Headers AS collection
	
	PROCEDURE Init
		CREATE CURSOR outputCache ( outLine M )
	ENDPROC
	
	PROCEDURE destroy
		IF this.bDirty == .T.
			this.flush()
		ENDIF 
		USE IN outputCache 
	ENDPROC
	
	PROCEDURE Write
		LPARAMETERS theHtml
		LOCAL lcOutput
		
		INSERT INTO outputCache values( theHtml )
		this.bDirty = .t.
		RETURN 
	ENDPROC
	
	HIDDEN PROCEDURE InternalWrite
		LPARAMETER lcOutput

		DECLARE INTEGER GetStdHandle in Win32API integer nHandleType
		declare integer WriteFile    in Win32API integer hFile, string @ cBuffer,;
				integer nBytes, integer @ nBytes2, integer @ nBytes3

		LOCAL lnOutHandle
		LOCAL lnBytesWritten
		LOCAL lnOverLappedIO 
		
		lnOutHandle=GetStdHandle(-11) 
		lnBytesWritten=0
		lnOverLappedIO=0
		WriteFile(lnOutHandle, @lcOutput, len(lcOutput), @lnBytesWritten, @lnOverLappedIO)
	ENDPROC
	
	PROCEDURE flushHeader
		LOCAL lcDefaultOutput
		LOCAL lcOutput
		LOCAL lcKey
		local i
		
		lcDefaultOutput=""
		lcOutput = ""

		FOR i = 1 TO this.Headers.Count
			lcKey = this.Headers.GetKey( i )
			IF !EMPTY( lcKey  ) THEN 
				lcOutput = lcOutput + lcKey + ": " + this.Headers.Item(i) + CHR(13) + CHR(10) 
			ENDIF 
		NEXT 
		
		IF this.Headers.getKey( "Content-type" ) == 0 THEN 
			lcOutput = lcOutput + "Content-type: text/html"+chr(13)+chr(10)
		ENDIF

		lcOutput = lcOutput + chr(13)+chr(10)
		this.InternalWrite( lcDefaultOutput + lcOutput )
		this.bHeaderOut = .T.
	ENDPROC
	
	PROCEDURE flush
		IF this.bDirty == .f. then
			RETURN
		ENDIF 

		LOCAL lcAlias
		LOCAL lcOutput
		
		IF this.bHeaderOut == .F. THEN
			this.flushHeader()
		ENDIF 
		
		lcAlias = ALIAS() 
		SELECT outputCache
		GO top
		SCAN
			lcOutput = outputCache.outLine
			this.InternalWrite( lcOutput )
		ENDSCAN
		SELECT( lcAlias )
	ENDPROC
ENDDEFINE

同樣的,新增 cgi05 以後,將她設置為主程式,重新編譯之後,再丟到對應路徑即可。