VFPCGI Day9

出自VFP Wiki

(修訂版本間差異)
跳轉到: 導航, 搜尋
 
第1行: 第1行:
[[Category:VFPCGI]]
[[Category:VFPCGI]]
=====VFPCGI的第九天=====
=====VFPCGI的第九天=====
-
當你知道規則之後,很快就能寫出一個類似 Request 的物件了~
+
有了 Request class,我們把 cgi05 改寫成 cgi06,不用自己再處理,改由 request class 去處理。
-
所以我們的 cgilib.prg 又多了一個 Request 類別:
+
 
 +
少掉前面的一堆處理,看起來是比較好一點了~
 +
下次來改寫 Request 來讓她可以處理中文。
 +
 
<pre>
<pre>
-
DEFINE CLASS REQUEST as Custom
+
*
-
TotalBytes = 0
+
* cgi06
-
RequestMethod = ""
+
*
-
ADD OBJECT QueryString AS collection
+
-
ADD OBJECT FormField AS collection
+
-
ADD OBJECT Cookies as collection
+
-
+
-
PROCEDURE INIT
+
-
DECLARE INTEGER GetStdHandle in Win32API integer nHandleType
+
-
declare integer ReadFile in Win32API integer hFile, string @ cBuffer,;
+
-
integer nBytes, integer @ nBytes2, integer @ nBytes3
+
-
+
-
LOCAL lcMethod
+
-
LOCAL lcQueryString
+
-
LOCAL lcContentLength, lnContentLength
+
-
LOCAL lcInput
+
-
LOCAL lnOverlappedIO
+
-
LOCAL lnInHandle
+
-
+
-
lcMethod = UPPER( GETENV( "REQUEST_METHOD" ) )
+
-
this.RequestMethod = lcMethod
+
-
lcQueryString = ""
+
-
+
-
DO CASE
+
-
CASE INLIST( lcMethod , "GET" )
+
-
* get environment variable: QUERY_STRING
+
-
lcQueryString = GETENV( "QUERY_STRING" )
+
-
this.ParseData( lcQueryString, this.QueryString )
+
-
CASE INLIST( lcMethod, "POST" )
+
-
&&lenght of input string in STDIN is in this environment variable
+
-
lcContentLength = GETENV("CONTENT_LENGTH")
+
-
IF LEN( lcContentLength ) > 0 THEN
+
-
lnContentLength=VAL( lcContentLength )
+
-
ELSE
+
-
lnContentLength = 0
+
-
ENDIF
+
-
IF lnContentLength > 0 THEN
+
SET PROCEDURE TO cgilib
-
&&get the input from STDIN
+
-
lnInHandle=GetStdHandle(-10)
+
-
lcInPut=REPLICATE(' ', lnContentLength )
+
-
lnOverlappedIO=0
+
-
ReadFile(lnInHandle, @lcInPut, lnContentLength, @lnContentLength, @lnOverlappedIO)
+
-
ELSE
+
-
lcInput=''
+
-
ENDIF
+
-
IF LEN( lcInput ) > 0 THEN
+
TRY
-
this.ParseData( lcInput, this.FormField )
+
LOCAL oResponse, oRequest
-
ENDIF
+
oResponse = CREATEOBJECT( "RESPONSE" )
-
OTHERWISE
+
oRequest = CREATEOBJECT( "REQUEST" )
-
ENDCASE
+
-
ENDPROC
+
-
+
-
HIDDEN PROCEDURE ParseData
+
-
LPARAMETERS cInput as String , oCollection as Collection
+
-
LOCAL i, nStart, nPos, nEqualPos
+
-
LOCAL lcStr, lcKey, lcValue
+
-
+
-
* parse it.
+
-
i = 1
+
-
nStart = 1
+
-
nPos=AT( "&", cInput, i )
+
-
IF nPos == 0 THEN
+
-
nPos = LEN( cInput )
+
-
ENDIF
+
-
DO WHILE nPos!=0
+
-
lcStr = SUBSTR( cInput, nStart, nPos-nStart )
+
-
nEqualPos = AT( "=", lcStr )
+
-
IF nEqualPos!=0 THEN
+
-
lcKey = SUBSTR( lcStr, 1, nEqualPos-1 )
+
-
lcValue = SUBSTR( lcStr, nEqualPos+1 )
+
-
oCollection.Add( lcValue, lcKey )
+
-
ENDIF
+
-
i=i+1
+
-
nStart = nPos + 1
+
-
nPos=AT( "&", cInput, i )
+
-
ENDDO
+
-
IF nStart < LEN(cInput) THEN
+
-
nPos = LEN( cInput )
+
-
lcStr = SUBSTR( cInput, nStart )
+
-
nEqualPos = AT( "=", lcStr )
+
-
IF nEqualPos!=0 THEN
+
-
lcKey = SUBSTR( lcStr, 1, nEqualPos-1 )
+
-
lcValue = SUBSTR( lcStr, nEqualPos+1 )
+
-
oCollection.Add( lcValue, lcKey )
+
-
ENDIF
+
-
ENDIF
+
-
ENDPROC
+
-
ENDDEFINE
+
-
</pre>
+
-
Request 這部份是最容易有問題的地方了~因為安全的漏洞往往來自於此。
+
* 取得目前的 Request Method
-
也正式因為如此,才會有人說,永遠不要相信使用者輸入的資料,無論如何都要作詳細的檢查。
+
LOCAL cInput
-
早期多半用 C 語言來寫 CGI 的時候,這邊常會犯的錯誤是,沒有預留足夠的空間來放這些輸入的字串,這也導致了 hacker 可以用緩衝區溢位的方式來進行攻擊。
+
cInput = "&lt;p&gt;REQUEST_METHOD=" + oRequest.RequestMethod + "&lt;/p&gt;"
-
我們這邊做的比較簡單,都自己寫程式去 parse 字串,然後放到 collection 裡面去。
+
* 因為要去處理的 collection 不一樣
-
依照上個範例的輸出結果,我想你應該知道可以利用 aline() 之類的函數來解,這會更方便些~
+
DO CASE
 +
CASE oRequest.RequestMethod == "POST"
 +
oCollection = oRequest.FormField
 +
OTHERWISE
 +
oCollection = oRequest.QueryString
 +
ENDCASE
 +
cInput = cInput + "&lt;p&gt;&lt;ul&gt;"
 +
FOR i=1 TO oCollection.Count
 +
cInput = cInput + "&lt;li&gt;" + oCollection.GetKey(i) + "=" + oCollection.Item(i) + "&lt;/li&gt;"
 +
ENDFOR
 +
cInput = cInput + "&lt;/ul&gt;&lt;/p&gt;"
-
這邊我們還沒處理 utf-8 與 % 的一些問題....同時也還沒補上 Request 的使用範例...
+
* 輸出成 HTML 囉~
 +
lcHtml = ""
 +
TEXT TO lcHtml NOSHOW ADDITIVE TEXTMERGE
 +
&lt;script language="javascript"&gt;
 +
function method_change( form )
 +
{
 +
switch ( form.cboMethod.value ) {
 +
case "GET": form.method = "GET"; break;
 +
case "POST": form.method = "POST"; break;
 +
}
 +
}
 +
&lt;/script&gt;
 +
&lt;form method="get" action="vfpcgi.exe"&gt;
 +
RequestMethod: &lt;select name="cboMethod" onChange="return method_change(this.form);"&gt;
 +
&lt;option value="GET" &lt;&lt;IIF(oRequest.RequestMethod=="GET", "selected", "")&gt;&gt; &gt;GET&lt;/option&gt;
 +
&lt;option value="POST" &lt;&lt;IIF(oRequest.RequestMethod=="POST", "selected", "")&gt;&gt; &gt;POST&lt;/option&gt;
 +
&lt;/select&gt;&lt;br/&gt;
 +
&lt;input type="text" name="txt" value=""/&gt;
 +
&lt;select name="cbo"&gt;
 +
&lt;option value="0" selected&gt;0&lt;/option&gt;
 +
&lt;option value="1"&gt;1&lt;/option&gt;
 +
&lt;option value="2"&gt;2&lt;/option&gt;
 +
&lt;/select&gt;&lt;br/&gt;
 +
&lt;input type="submit" value="Submit"/&gt;
 +
&lt;input type="reset" value="Reset"/&gt;
 +
&lt;/form&gt;
 +
&lt;&lt;cInput&gt;&gt;
 +
ENDTEXT
 +
 
 +
oResponse.Write( lcHtml )
 +
CATCH TO oError
 +
oResponse.Write( oError.Message )
 +
FINALLY
 +
ENDTRY
 +
</pre>

在2006年11月22日 (三) 14:59的最新修訂版本

VFPCGI的第九天

有了 Request class,我們把 cgi05 改寫成 cgi06,不用自己再處理,改由 request class 去處理。

少掉前面的一堆處理,看起來是比較好一點了~ 下次來改寫 Request 來讓她可以處理中文。

*
* cgi06
*

SET PROCEDURE TO cgilib

TRY 
	LOCAL oResponse, oRequest
	oResponse = CREATEOBJECT( "RESPONSE" )
	oRequest = CREATEOBJECT( "REQUEST" )

	* 取得目前的 Request Method
	LOCAL cInput
	cInput = "<p>REQUEST_METHOD=" + oRequest.RequestMethod + "</p>"

	* 因為要去處理的 collection 不一樣
	DO CASE 
		CASE oRequest.RequestMethod == "POST"
			oCollection = oRequest.FormField
		OTHERWISE 
			oCollection = oRequest.QueryString
	ENDCASE 
	cInput = cInput + "<p><ul>"
	FOR i=1 TO oCollection.Count
		cInput = cInput + "<li>" + oCollection.GetKey(i) + "=" + oCollection.Item(i) + "</li>"
	ENDFOR
	cInput = cInput + "</ul></p>"

	* 輸出成 HTML 囉~
	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(oRequest.RequestMethod=="GET", "selected", "")>> >GET</option>
		<option value="POST" <<IIF(oRequest.RequestMethod=="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>
	<<cInput>>
	ENDTEXT 

	oResponse.Write( lcHtml )
CATCH TO oError
	oResponse.Write( oError.Message )
FINALLY 
ENDTRY