CGI - How to process HTML forms!

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
Julcar
Posts: 45
Joined: Oct 19, 2010 18:52

CGI - How to process HTML forms!

Postby Julcar » Feb 21, 2013 18:48

Hi all, I want to share with the community this code for processing HTML forms, some very useful with CGI:

Code: Select all

Sub PrintHeaders()
  Print !"Content-type:text/html;Charset=us-ascii\n"
End Sub

Function SplitVar(query as string, arg as string) as string
  Dim as string value, result
  If InStr(query, arg) <> 0 Then
    value = Mid(query, InStr(query, arg), len(query))
    If Instr(value, "&") <> 0 Then
      result = Mid(value, len(arg) + 2, Instr(value, "&") - len(arg) - 2)
    Else
      result = Mid(value, len(arg) + 2, len(value))
    End If
  Else
    result = ""
  End If
  SplitVar = result
End Function

Function ReadStdin() as string
  Dim numChars as integer
  Dim postQuery as string
  numChars = val(environ("CONTENT_LENGTH"))
  open cons for input as #1
  postQuery = space(numChars)
  get #1,,postQuery
  close #1
  ReadStdin = postQuery
End Function

Function QueryString(arg as string) as string
  If environ("REQUEST_METHOD") = "GET" Then
    QueryString = SplitVar(environ("QUERY_STRING"), arg)
  Else
    QueryString = ""
  End If
End Function

Function Post(query as string, arg as string) as string
  If environ("REQUEST_METHOD") = "POST" Then
    Post = SplitVar(query, arg)
  Else
    Post = ""
  End If
End Function

'Now we can print the page content

PrintHeaders()

Print "<html>"
Print "<head>"
Print "<body>"
Print "<form id=""personal-data"" method=""post"" action=""test.exe"">"
Print "<div style=""text-align:center;"">"
Print "<h2>Fill this form with your data</h2>"
Print "First Name: <input type=""text"" name=""firstname"" /><br />"
Print "Last Name: <input type=""text"" name=""lastname"" /><br />"
Print "City: <input type=""text"" name=""city"" /><br />"
Print "Country: <input type=""text"" name=""country"" /><br />"
Print "<input type=""submit"" id=""send"" value=""Send"" />"
Print "</div></form>"
Print "<div style=""text-align:center;"">"
If environ("REQUEST_METHOD") = "POST" Then
Dim as String strPost = ReadStdin()
Print "<em>Your data was successfully receipted!</em><br>"
Print "<p>Your name is: <strong>"& Post(strPost, "firstname") &" "& Post(strPost, "lastname") &"</strong></p>"
Print "<p>And you lives on: <strong>"& Post(strPost, "city") &" - "& Post(strPost, "country") &"</strong> </p>"
Else
Print "<em>No data sent yet!</em>"
End If
Print "<div>"
Print "</body>"
Print "</head>"
Print "</html>"


Just compile as TEST.EXE and run as CGI on a webserver like TinyWeb: http://www.ritlabs.com/en/products/tinyweb/

You must only create a CGI-BIN folder into your root and there place the EXE compiled, now go to your browser and prompt http://localhost/cgi-bin/test.exe and you will see the form ready to work.

Please comment about my code!

Regards
teccs
Posts: 6
Joined: Dec 24, 2006 20:27
Location: Cheyenne, WY
Contact:

Re: CGI - How to process HTML forms!

Postby teccs » Dec 19, 2014 0:25

I am a newbie. Can this be made to work in Linux on ubuntu with apache?
Thanks you in advance.
JohanD
Posts: 11
Joined: Dec 23, 2014 7:06

Re: CGI - How to process HTML forms!

Postby JohanD » Dec 23, 2014 7:13

Yes, easily.. I just worked it out myself.
Compile it, and place it (standard ubuntu) in /usr/lub/cgi-bin
Create a form, with post action, and start the compiled freebasic with it.
Works well.

Note that you need to alter above to decode the url-encoded recieved text, otherwise % and + signs are added.
Not at my system now, I will post the altered version with auto translation later this day.
JohanD
Posts: 11
Joined: Dec 23, 2014 7:06

Re: CGI - How to process HTML forms!

Postby JohanD » Dec 23, 2014 16:34

My changes:

Code: Select all

Function URLDecode(arg as string) as string
      Dim as string char, query, value, rlt
      Dim i as integer
      char = "&H"
      For i = 0 To len(arg)
        query = Mid(arg, i, 1)
        If query = "%" Then
          value = chr(valint(char & Mid(arg, i + 1, 2)))
          rlt = rlt & value
          i = i + 2
        ElseIf query = "+" Then
          value = " "
          rlt = rlt & value
        Else
          rlt = rlt & query
        End If
      Next
      URLDecode = rlt
End Function


Code: Select all

Function SplitVar(query as string, arg as string) as string
  Dim as string value, rlt
  If InStr(query, arg) <> 0 Then
    value = Mid(query, InStr(query, arg), len(query))
    If Instr(value, "&") <> 0 Then
      rlt = Mid(value, len(arg) + 2, Instr(value, "&") - len(arg) - 2)
    Else
      rlt = Mid(value, len(arg) + 2, len(value))
    End If
  Else
    rlt = ""
  End If
  SplitVar = URLDecode(rlt)   <================================================= !!
End Function

Function ReadStdin() as string
  Dim numChars as integer
  Dim postQuery as string
  numChars = val(environ("CONTENT_LENGTH"))
  open cons for input as #1
  postQuery = space(numChars)
  get #1,,postQuery
  close #1
  ReadStdin = postQuery
End Function

Function QueryString(arg as string) as string
  If environ("REQUEST_METHOD") = "GET" Then
    QueryString = SplitVar(environ("QUERY_STRING"), arg)
  Else
    QueryString = ""
  End If
End Function

Function Post(query as string, arg as string) as string
  If environ("REQUEST_METHOD") = "POST" Then
    Post = SplitVar(query, arg)
  Else
    Post = ""
  End If
End Function
Julcar
Posts: 45
Joined: Oct 19, 2010 18:52

Re: CGI - How to process HTML forms!

Postby Julcar » Dec 28, 2014 8:39

Here are the code translated to langqb

Code: Select all

FUNCTION ReadStdin$
  IF ENVIRON$("REQUEST_METHOD") = "POST" THEN
    numChars = VAL(ENVIRON$("CONTENT_LENGTH"))
    postQuery$ = INPUT$(numChars)
    ReadStdin$ = postQuery$
  ELSE
    ReadStdin$ = ""
  END IF
END FUNCTION

FUNCTION SplitVar$ (strQuery$, arg$, delimiter$)
  result$ = ""
  IF INSTR(strQuery$, arg$) <> 0 THEN
    strVal$ = MID$(strQuery$, INSTR(strQuery$, arg$), LEN(strQuery$))
    IF INSTR(strVal$, delimiter$) <> 0 THEN
      result$ = MID$(strVal$, LEN(arg$) + 2, INSTR(strVal$, delimiter$) - LEN(arg$) - 2)
    ELSE
      result$ = MID$(strVal$, LEN(arg$) + 2, LEN(strVal$))
    END IF
  END IF
  SplitVar$ = result$
END FUNCTION

FUNCTION UnEscape$ (strQuery$)
  result$ = ""
  FOR i = 1 TO LEN(strQuery$)
    char$ = MID$(strQuery$, i, 1)
    SELECT CASE char$
      CASE "%"
        value$ = CHR$(VAL("&H" + MID$(strQuery$, i + 1, 2)))
        result$ = result$ + value$
        i = i + 2
      CASE "+"
        value$ = " "
        result$ = result$ + value$
      CASE ELSE
        result$ = result$ + char$
    END SELECT
  NEXT
  UnEscape$ = result$
END FUNCTION

FUNCTION Replace$ (strQuery$, lookFor$, replaceWith$)
  result$ = strQuery$
  DO
    foundPos = INSTR(result$, lookFor$)
    IF foundPos <> 0 THEN
      startPos = foundPos - 1
      nextPos = foundPos + LEN(lookFor$)
      strLeft$ = LEFT$(result$, startPos)
      strRight$ = MID$(result$, nextPos, LEN(result$))
      result$ = strLeft$ + replaceWith$ + strRight$
    ELSE
     EXIT DO
    END IF
  LOOP
  Replace$ = result$
END FUNCTION

COMMON SHARED StdinQuery$
StdinQuery$ = ReadStdin$

FUNCTION Post$ (arg$)
  Post$ = UnEscape$(SplitVar$(StdinQuery$, arg$, "&"))
END FUNCTION

FUNCTION QueryString$ (arg$)
  QueryString$ = UnEscape$(SplitVar$(ENVIRON$("QUERY_STRING"), arg$, "&"))
END FUNCTION
jdmcbride
Posts: 21
Joined: Aug 06, 2016 16:13

Re: CGI - How to process HTML forms!

Postby jdmcbride » Aug 21, 2016 1:52

Two years later... Thank you.
JohanD
Posts: 11
Joined: Dec 23, 2014 7:06

Re: CGI - How to process HTML forms!

Postby JohanD » Jun 29, 2019 13:04

Lol.. 2 years later I want to pick off where I left..
How to do cookie handling ?
Julcar
Posts: 45
Joined: Oct 19, 2010 18:52

Re: CGI - How to process HTML forms!

Postby Julcar » Jun 30, 2019 10:09

JohanD wrote:Lol.. 2 years later I want to pick off where I left..
How to do cookie handling ?


Is coded in QB lang, but should be easy to convert to FB lang

As SetCookie modifies HTTP headers, you must call the function BEFORE any output has been sent to client's web browser

Code: Select all

FUNCTION SetCookie$(cookieName$, cookieValue$, domain$, path$, expiresDate$, maxAgeTime, secure, httpOnly)
  DIM strOutput$
  'Add standard parameters
  strOutput$ = "Set-Cookie:" + CHR$(32) + cookieName$ + CHR$(61) + cookieValue$
  IF domain$ <> "" THEN
    strOutput$ = strOutput$ + CHR$(59) + CHR$(32) + "Domain=" + domain$
  END IF
  IF path$ <> "" THEN
    strOutput$ = strOutput$ + CHR$(59) + CHR$(32) + "Path=" + path$
  END IF
  IF expiresDate$ <> "" THEN
    'FIXME: validate standard date format Wdy, DD Mon YYYY HH:MM:SS GMT
    strOutput$ = strOutput$ + CHR$(59) + CHR$(32) + "Expires=" + expiresDate$
  END IF
  IF maxAgeTime > 0 THEN
    strOutput$ = strOutput$ + CHR$(59) + CHR$(32) + "Max-Age=" + LTRIM$(STR$(maxAgeTime))
  END IF
  IF secure = 1 THEN
    strOutput$ = strOutput$ + CHR$(59) + CHR$(32) + "Secure"
  END IF
  IF httpOnly = 1 THEN
    strOutput$ = strOutput$ + CHR$(59) + CHR$(32) + "HttpOnly"
  END IF
  'Add the line feed
  strOutput$ = strOutput$ + CHR$(13) + CHR$(10)
  SetCookie$ = strOutput$
  strOutput$ = ""
END FUNCTION

FUNCTION GetCookie$(cookieName$)
  DIM RawCookieStr$
  RawCookieStr$ = ENVIRON$("HTTP_COOKIE")
  IF cookieName$ <> "" THEN
    GetCookie$ = SplitVar$(RawCookieStr$, cookieName$, CHR$(59))
  ELSE
    GetCookie$ = RawCookieStr$
  END IF
  RawCookieStr$ = ""
END FUNCTION
JohanD
Posts: 11
Joined: Dec 23, 2014 7:06

Re: CGI - How to process HTML forms!

Postby JohanD » Jun 30, 2019 18:32

Thanks sir, I need to take a deep look into this
bcohio2001
Posts: 548
Joined: Mar 10, 2007 15:44
Location: Ohio, USA
Contact:

Re: CGI - How to process HTML forms!

Postby bcohio2001 » Jun 30, 2019 22:30

Here is something I use in my own creation of a web browser, still WIP.

Cookie.bi

Code: Select all

Type CookData
   As String CookName
   As String CookValue
   As Double Expires
   As String Path
   As String Host
End Type

Type Cook
   As Integer CookieCount
   As CookData CookieArray(Any)
   As Long LocalTimeBias 'minute difference between user and UTC (GMT)
   '
   Declare Constructor() 'load cookie file
   Declare Destructor() 'saves final cookie file
   Declare Function SendCookie(Host As String, Path As String) As String
   Declare Sub RecCookie(Header As String, Host As String, Path As String)
   Declare Function IsCurrent(Index As Integer) As Integer
End Type

Cookie.bas

Code: Select all

Constructor Cook()
'load in cookies
'ReDim CookieArray(0)
If FileExists(ExePath + "/Cookie.txt") Then
   Dim As Integer ff = FreeFile
   Open ExePath + "/Cookie.txt" For Input As #ff
   While Eof(ff) = 0
      ReDim Preserve CookieArray(CookieCount)
      Input #ff, CookieArray(CookieCount).Host
      Input #ff, CookieArray(CookieCount).Path
      Input #ff, CookieArray(CookieCount).CookName
      Input #ff, CookieArray(CookieCount).CookValue
      Input #ff, CookieArray(CookieCount).Expires
      'perm or non expired?
      If IsCurrent(CookieCount) = 1 Then
         'keep
         CookieCount += 1
      EndIf
   Wend
   Close #ff
EndIf
End Constructor

Destructor Cook()
'save non expired cookies
If FileExists(ExePath + "/Cookie.txt") Then Kill(ExePath + "/Cookie.txt")
If CookieCount Then
   Dim As Integer x, Valid, ff
   'any "Valid"
   For x = 0 To CookieCount - 1
      If IsCurrent(x) = 1 And CookieArray(x).CookValue <> "" Then Valid += 1
   Next
   If Valid Then
      ff = FreeFile
      Open ExePath + "/Cookie.txt" For Output As #ff
      For x = 0 To CookieCount - 1
         If IsCurrent(x) = 1 And CookieArray(x).CookValue <> "" Then
            Print #ff, CookieArray(x).Host
            Print #ff, CookieArray(x).Path
            Print #ff, CookieArray(x).CookName
            Print #ff, CookieArray(x).CookValue
            Print #ff, CookieArray(x).Expires
         EndIf
      Next
   EndIf
EndIf
End Destructor

Function Cook.SendCookie(Host As String, Path As String) As String
   If CookieCount = 0 Then Return ""
   Dim As String R = "" 'return value
   Dim As String CookieList = "" 'listing of cookies to add
   Dim As Integer x, S
   Dim As String PathOnly
   'Cookie: <name>=<value> [;<name>=<value>]...
   While x < CookieCount
      If IsCurrent(x) Then
         If CookieArray(x).Host = Host Then
            'exact match, check path
            If Left(Path, Len(CookieArray(x).Path)) = CookieArray(x).Path Then
               'Path match
               S = 1
            Else
               S = 0
            EndIf
         Else
            'check for partal match (global host)
            If Right(Host, Len(CookieArray(x).Host)) = CookieArray(x).Host Then
               S = 1 'flag to add
            Else
               S = 0 'do not add
            EndIf
         EndIf
         If S > 0 And Len(CookieArray(x).CookValue) > 0 Then
            'add
            If Len(CookieList) Then CookieList += ";"
            CookieList += CookieArray(x).CookName + "=" + CookieArray(x).CookValue
         EndIf
      EndIf
      x += 1
   Wend
   If Len(CookieList) Then R = "Cookie: " + CookieList 'add this to header
   Return R
End Function

Sub Cook.RecCookie(Header As String, Host As String, Path As String)
   Dim As Integer CookieStart = InStr(Header, "Set-Cookie:")
   Dim As Integer S, F
   Dim As CookData TempCookie
   Dim As String CookiePart
   '
   While CookieStart
      S = InStr(CookieStart, Header, Chr(13)) 'end of set-cookie
      CookiePart = Mid(Header, CookieStart, S - CookieStart)
      'Cookie name
      S = InStr(CookiePart, " ") + 1
      F = InStr(S, CookiePart, "=")
      TempCookie.CookName = Mid(CookiePart, S, F - S)
      'Cookie value
      S = F + 1
      F = InStr(S, CookiePart, ";")
      TempCookie.CookValue = Mid(CookiePart, S, F - S)
      'expires
      S = InStr(CookiePart, "expires=")
      If S Then
         'has expire
         S += 8
         F = InStr(S, CookiePart, ";")
         TempCookie.Expires = HttpDate(Mid(CookiePart, S, F - S)) 'GMT
      Else
         TempCookie.Expires = 0 'permanent or session
      EndIf
      'host
      S = InStr(CookiePart, "domain=")
      If S Then
         'has domain
         S += 7
         F = InStr(S, CookiePart, ";")
         TempCookie.Host = Mid(CookiePart, S, F - S)
      Else
         'SEE COMMENTS AT END OF FILE
         'session cookie
         TempCookie.Host = Host
         TempCookie.Expires = -1 'mark as so
      EndIf
      'path spec for host
      S = InStr(CookiePart, "path=")
      If S Then
         'has path
         S += 5
         F = InStr(S, CookiePart, ";")
         TempCookie.Path = Mid(CookiePart, S, F - S)
      Else
         'SEE COMMENTS AT END OF FILE
         S = InStrRev(Path, "/")
         If S Then
            TempCookie.Path = Left(Path, S)
         Else
            TempCookie.Path = "/"
         EndIf
      EndIf
      'search cookie array for one already set
      If CookieCount Then
         For S = 0 To CookieCount - 1
            If TempCookie.CookName = CookieArray(S).CookName And TempCookie.Host = CookieArray(S).Host And TempCookie.Path = CookieArray(S).Path Then
               CookieArray(S).CookValue = TempCookie.CookValue
               CookieArray(S).Expires = TempCookie.Expires
               Exit For
            EndIf
         Next
      Else
         S = 0
      EndIf
      If S = CookieCount Then
         'add
         ReDim Preserve CookieArray(CookieCount)
         CookieArray(S).Host = TempCookie.Host
         CookieArray(S).Path = TempCookie.Path
         CookieArray(S).CookName = TempCookie.CookName
         CookieArray(S).CookValue = TempCookie.CookValue
         CookieArray(S).Expires = TempCookie.Expires
         CookieCount += 1
      EndIf
      CookieStart = InStr(CookieStart + 5, Header, "Set-Cookie:")
   Wend
End Sub

Function Cook.IsCurrent(Index As Integer) As Integer
   If CookieArray(Index).Expires < 0 Then Return 2 'Session cookie
   If CookieArray(Index).Expires = 0 Then Return 1 'permenant cookie
   If CookieArray(Index).Expires > Now + TimeSerial(0, LocalTimeBias, 0) Then Return 1 'not expired
   Return 0 'EXPIRED
End Function

/'
Specifying the domain name, using the pattern domain=domain_name, is optional for persistent cookies and is used to indicate the end of the domain for which the cookie is valid.
Session cookies that specify a domain are rejected.
If the specified domain name ending matches the request, the cookie tries to match the path to determine if the cookie should be sent.
For example, if the domain name ending is .microsoft.com, requests to home.microsoft.com and support.microsoft.com would be checked to see if the specified pattern matches the request.
The domain name must have at least two or three periods in it to prevent cookies from being set for widely used domain name endings, such as .com, .edu, and co.jp.
Allowable domain names would be similar to .microsoft.com, .someschool.edu, and .someserver.co.jp. Only hosts within the specified domain can set a cookie for a domain.

Setting the path, using the pattern path=some_path, is optional and can be used to specify a subset of the URLs for which the cookie is valid.
If a path is specified, the cookie is considered valid for any requests that match that path.
For example, if the specified path is /example, requests with the paths /examplecode and /example/code.htm would match.
If no path is specified, the path is assumed to be the path of the resource associated with the Set-Cookie header.
'/

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 2 guests