Page 1 of 1

[Implemented] A CGI library compatible cross OS

Posted: Tue Jan 20, 2004 5:02 pm
by NelsonN
This is a seriously needed addition. I can program descent Windows CGI tools but not with the Linux version because of a lack of a CGI library for Linux.

Posted: Wed Jan 21, 2004 9:30 pm
by griz
I too would like to learn how to create CGIs with the Linux version of PB.

Perhaps El_Choni will port his CGI library? :wink:

Does anyone have alternate suggestions?

Posted: Thu Jan 22, 2004 3:36 am
by NelsonN
griz wrote: Does anyone have alternate suggestions?
I have been looking for an alternative but no luck. It really is needed.

But to be fare, perhaps it is us who are lacking. :)

Maybe El_Choni will port it to Linux. Where is El_Choni these days, anyway?

Posted: Thu Jan 22, 2004 1:28 pm
by El_Choni
I'm not dead, but I can't port it to Linux since I don't know the Linux API and I don't even have Linux installed anywhere. But it must be piece of cake to code these functions in C and build a library with the Library SDK in the PureBasic for Linux version (I guess it includes a SDK, right?)

Cya,

Posted: Thu Jan 22, 2004 4:18 pm
by NelsonN
Yes, the Linux version has an SDK.

But I am not that advanced of a programmer, especially in Linux. Which is why I am willing to hand over a few bucks :)

Posted: Thu Jan 22, 2004 4:39 pm
by El_Choni
That's nice to hear but, as I said, I don't have enough knowledge to code anything for Linux different than php or perl. But if some Linux code offers to help you, I'll help him to port the functions (for free).

Regards,

Posted: Sat Jan 24, 2004 6:14 pm
by Triskelios
Well, NelsonN ended up contacting me on freenode (IRC) about it, and I agreed to give a shot at writing a POSIX version of the library in C (more motivated by possible payment, since I'm certain that this isn't the right way to approach server-side scripting at all... =P). Since I can't read intel asm at all, I'll take that offer of assistance.

Posted: Sat Jan 24, 2004 6:22 pm
by El_Choni
Ok, let's do it: mcalderon_inicia.es

I can't start with this until Thursday. Maybe you can have a look at the Readme.txt file included in the lib so you know each function's job. Probably, I'll update the Windows version, too.

Cya,

Posted: Fri Sep 09, 2005 8:10 pm
by FloHimself
any news on this one?

Posted: Sat Sep 10, 2005 10:11 am
by DarkDragon
griz wrote:I too would like to learn how to create CGIs with the Linux version of PB.

Perhaps El_Choni will port his CGI library? :wink:

Does anyone have alternate suggestions?
PrintN/Print and getenv_ are the whole needed commands ;) .

Posted: Thu Mar 16, 2006 9:02 pm
by ricardo
Any news?

Posted: Fri Mar 17, 2006 9:24 am
by blueznl
i guess waiting for pb4 for linux may solve your issues?

Posted: Fri Mar 17, 2006 11:19 am
by Nik
The fact is there isn't a issue since Linux has no graphical console the normal console commands + getenv_ are everything you need on Linux, nor problem in sight

Purebasic CGI Library

Posted: Sat Dec 02, 2006 4:55 pm
by StanDan
I know this thread is old but I might as well post this. I was looking for the exact same thing, so I wrote my own. It's based loosely on the Perl 1.x cgi-lib.pl code. So it should work in most situations. It's not blazingly fast for PB code, it just works. It's also very easy to use. It's as simple as:

Code: Select all

XIncludeFile "cgi.pb"
ReadParse()
; To print all arguments
ForEach CGIArgs()
  PrintN("<tr>")
  PrintN("<td>"+CGIArgs()\name+"</td>")
  PrintN("<td>"+CGIArgs()\value+"</td>")
  PrintN("</tr>")
Next
; To get a specific form argument
someArg.s = GetCGIArg("someArg")
It just reads the arguments into a linked list called CGIArgs(), each element is a structure with attributes called name and value. Very simple. Comments, patches, suggestions are very welcome. I have tested this with Apache 2 on Linux. Haven't tried IIS yet but it should work. I'm declaring this code public domain, use it however you want.

Code: Select all

OpenConsole()

Structure CGIArg
  name.s
  value.s
EndStructure

Global NewList CGIArgs.CGIArg(), CGIMaxPostSize = 10000, CGIHeaderFlag = 0

Procedure Header()
  If CGIHeaderFlag = 0
    PrintN("Content-type: text/html"+Chr(10)+Chr(10))
    CGIHeaderFlag = 1
  EndIf
EndProcedure

Procedure CGIError(error.s)
  Header()
  PrintN("<h3 class='cgiError'>"+error+"</h3>")
  End
EndProcedure

Procedure CGIAssert(val.l)
  If val = 0
    Debug "Dying on CGIAssert statement."
    CGIError("Error 500: Internal Server Error")
  EndIf
EndProcedure

; Return the binary number corresponding to the character 0-9a-f, 1-15
Procedure.l GetNum(thechar.l)
  ; Handle 0-9
  If thechar >= 48 And thechar <= 57
    ProcedureReturn thechar - 48

  ; Handle a-f
  ElseIf thechar >= 97 And thechar <= 102
    ProcedureReturn 10 + (thechar - 97)
    
  ; Handle A-F
  ElseIf thechar >= 65 And thechar <= 70
    ProcedureReturn 10 + (thechar - 65)
   
  Else
    Debug "Non hex character passed to GetNum()"
    ProcedureReturn -1
  EndIf
EndProcedure

; Convert a hexidecimal character string into its binary representation.
Procedure.l ValH(nums.s)
  Define.l strlen = 0, pos =0, answer = 0
  strlen = Len(nums)
  pos = strlen
  
  While pos > 0
    answer = answer + Pow(16, pos -1) * GetNum(Asc(Mid(nums, strlen - pos+1, 1)))
    pos = pos - 1
  Wend
  
  ProcedureReturn answer
EndProcedure

; Check if a character is valid hexidecimal.
Procedure.l IsHex(thechar.l)
  If (thechar >= 48 And thechar <= 57) Or (thechar >= 97 And thechar <= 102) Or (thechar >= 65 And thechar <= 70) 
    ProcedureReturn 1
  Else
    ProcedureReturn 0
  EndIf 
EndProcedure

; Decode URL ecoding %20 = ' ' etc.
Procedure.s URLDecode(str.s)
  Define.s ret = str, temp = ""
  Define.l currentPos = 1, prevPos = 1
  Define.s byte
  
  ReplaceString(str, "+", " ", 2)
  currentPos = FindString(str, "%", currentPos)
  While currentPos > 0
    temp = temp + Mid(str, prevPos, currentPos - prevPos)
    Debug temp
    byte = Mid(str, currentPos+1, 2)
    Debug "'"+byte+"'"
    If Len(byte) <> 2
      Break
    EndIf
    If IsHex(Asc(Mid(byte, 1, 1))) And IsHex(Asc(Mid(byte, 2, 1))) And byte <> "00"
      temp = temp + Chr(ValH(LCase(byte)))
      Debug "'"+Chr(ValH(LCase(byte)))+"'"
      currentPos = currentPos + 3
    Else
      temp = temp + "%" + byte
      currentPos = currentPos + 3
    EndIf 
    prevPos = currentPos
    currentPos = FindString(str, "%", currentPos)
  Wend
  If temp <> ""
    temp = temp + Mid(str, prevPos, Len(str))
    ret = temp
  EndIf
  ProcedureReturn ret
EndProcedure

Procedure ReadParse()
  Define.s method = GetEnvironmentVariable("REQUEST_METHOD")
  Define.s type = GetEnvironmentVariable("CONTENT_TYPE")
  Define.s query = ""
  
  If method="" Or method = "GET" Or method = "HEAD" Or type = "application/x-www-form-urlencoded"
    If method = "GET"
      query = GetEnvironmentVariable("QUERY_STRING")
    ElseIf method = "POST"
      Define.l length, *ptr, res
      length = Val(GetEnvironmentVariable("CONTENT_LENGTH"))
      If length < CGIMaxPostSize
        *ptr = AllocateMemory(length)
        res = ReadConsoleData(*ptr, length)
        If res <> length
          Debug "CONTENT_LENGTH does not match input"
        EndIf
        query = PeekS(*ptr)
        FreeMemory(*ptr)
      Else
        Debug "Skipping since CONTENT_LENGTH exceeds CGIMaxPostSize"
      EndIf
      ProcedureReturn
    Else
      Debug "Uknown request method."
      ProcedureReturn
    EndIf
    
    Define.l args = 0, i = 0    
    args = CountString(query, "&") + 1
    While i < args
      Define.s temp
      i = i + 1
      temp = StringField(query, i, "&")
      AddElement(CGIArgs())
      CGIArgs()\name = URLDecode(StringField(temp, 1, "="))
      CGIArgs()\value = URLDecode(StringField(temp, 2, "="))
    Wend
  EndIf
EndProcedure

Procedure.s GetCGIArg(name.s)
  ForEach CGIArgs()
    If CGIArgs()\name = name
      ProcedureReturn CGIArgs()\value
    EndIf
  Next
  ProcedureReturn ""
EndProcedure

Procedure PrintCGIArgs()
  Header()
  PrintN("<table><tr><td>Name</td><td>Value</td></tr>")
  ReadParse()
  ForEach CGIArgs()
    PrintN("<tr>")
    PrintN("<td>"+CGIArgs()\name+"</td>")
    PrintN("<td>"+CGIArgs()\value+"</td>")
    PrintN("</tr>")
  Next
  PrintN("</table>")
EndProcedure
One thing I'm going to do when I get around to it is write the parser for CONTENT_TYPE = "multipart/form-data". I'll post it when I get a project that requires file upload.