I would certainly be interested to see this, and any configuration info on testing and developing PB exes within XAMPP, should anyone have already done this.Seymour Clufley wrote:I wrote a CGI include that handles all the communication coming in and out of a PB exe. I've been using it for ages and it also handles returning images (although I haven't tested that for a while). If it would help, I'll post it.
CGI Survival Guide
- greyhoundcode
- Enthusiast
- Posts: 112
- Joined: Sun Dec 30, 2007 7:24 pm
Re: CGI Survival Guide
Re: CGI Survival Guide
As I have never done any web development, any info is wecome.
About those PHP frameworks, I assume those provide a number of API's, but for what kind of functions?
About those PHP frameworks, I assume those provide a number of API's, but for what kind of functions?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
( The path to enlightenment and the PureBasic Survival Guide right here... )
- greyhoundcode
- Enthusiast
- Posts: 112
- Joined: Sun Dec 30, 2007 7:24 pm
Re: CGI Survival Guide
The frameworks typically do two things - they provide structure, often in the form of the MVC pattern, and they offer a number of classes solving common problems, ranging from pagination of database queries (you see that in action every time you perform a search on a forum such as this) to setting and retrieving cookies. The list is extensive and you could get a good insight by visiting the Kohana documentation - which is a personal favourite of mine.
The MVC (model - view - controller) pattern referred to is a way of separating presentation and logic, so that you avoid a spaghetti soup of code involving functionality and output. MVC is not restricted to web apps, nor am I a particular expert on the ins and outs of it. I certainly don't want to teach better programmers that I to suck eggs, but basically say the framework gets a request such as website.net/boats/view/504.
The request is then routed to the Boats controller, which in turn uses its View method to query the Boats model (models handle interaction with the database). 504 might be a table-id within the Boats table of the database.
On retrieving the necessary information, the controller will then call a View, which is primarily HTML mixed with purely presentational code elements. The view is then outputted to the browser.
That might or might not sound overly complicated - but I'd be happy to clarify any points. It's a system that can take a day or two to wrap your head around but makes it really fast to code.
The MVC (model - view - controller) pattern referred to is a way of separating presentation and logic, so that you avoid a spaghetti soup of code involving functionality and output. MVC is not restricted to web apps, nor am I a particular expert on the ins and outs of it. I certainly don't want to teach better programmers that I to suck eggs, but basically say the framework gets a request such as website.net/boats/view/504.
The request is then routed to the Boats controller, which in turn uses its View method to query the Boats model (models handle interaction with the database). 504 might be a table-id within the Boats table of the database.
On retrieving the necessary information, the controller will then call a View, which is primarily HTML mixed with purely presentational code elements. The view is then outputted to the browser.
That might or might not sound overly complicated - but I'd be happy to clarify any points. It's a system that can take a day or two to wrap your head around but makes it really fast to code.
-
- Addict
- Posts: 1264
- Joined: Wed Feb 28, 2007 9:13 am
- Location: London
Re: CGI Survival Guide
Okay, as requested here's my CGI framework. It was based on code from around the forums, which I think was mainly by Rings.
The goal with this code was to make as small a CGI system as possible, so that I could forget about it and concentrate on receiving request strings and replying to them.
For POST requests, any information will be in the string cgi\PostData. I think GET parameters come in through cgi\QueryString but I never use that method so can't remember how it works.
Anyway you can reply to the request using one of 5 procedures:
Then save it in your local server folder as "pb.exe".
Then save this as an HTML file in your local server folder:
That should be it. Open the HTML file with your localserver prefix. Hopefully an image will be displayed!
I think other content types could be handled in a similar way, but as yet I've had no need of them so haven't accommodated them yet.
As for XAMPP, I've been using it for years to build websites offline. I can't remember the settings. I'll examine my conf files and post back if I can work out what is necessary to make it work. From what I remember, my difficulty with XAMPP was getting it to work in the first place (folders etc.) - after that, getting it to work with PB executables was easy.
As to the PB code, everything up till the linecan be placed in an include file so you can forget all about the CGI system and concentrate on the requests and replies.
I am currently using this code as the basis for a fairly complex Ajax framework. It's done very simply: the cgi\PostData is stringfielded to get all the "aspects" of a completely custom request. A reply is then formulated and sent back with similar dressing to a JavaScript system at the client end.
Obviously it can also handle Sjax requests.
Or you can use it as simply as in the demo. But to be honest I hate CGI pages; Ajax is a far more sensible way to do things.
The goal with this code was to make as small a CGI system as possible, so that I could forget about it and concentrate on receiving request strings and replying to them.
For POST requests, any information will be in the string cgi\PostData. I think GET parameters come in through cgi\QueryString but I never use that method so can't remember how it works.
Anyway you can reply to the request using one of 5 procedures:
- ReplyText(text.s)
- ReplyHTML(html.s)
- ReplyLocation(URLorFilename.s)
- ReplyImage(imagenumber.i,compressionformat.i)
- ReplyImageFile(filename.s,file's compression format.i)
Code: Select all
Structure CommonGatewayInterface
AuthType.s
ContentLength.i
ContentType.s
DocumentRoot.s
GatewayInterface.s
PathInfo.s
PathTranslated.s
QueryString.s
RemoteAddr.s
RemoteHost.s
RemoteIdent.s
RemotePort.s
RemoteUser.s
RequestURI.s
RequestMethod.s
ScriptName.s
ScriptFilename.s
ServerAdmin.s
ServerName.s
ServerPort.s
ServerProtocol.s
ServerSignature.s
ServerSoftware.s
HTTPAccept.s
HTTPAcceptEncoding.s
HTTPAcceptLanguage.s
HTTPCookie.s
HTTPForwarded.s
HTTPHost.s
HTTPPragma.s
HTTPReferer.s
HTTPUserAgent.s
PostData.s
EndStructure
Global cgi.CommonGatewayInterface
Procedure GetCGIVariables()
cgi\AuthType = GetEnvironmentVariable("AUTH_TYPE")
cgi\ContentLength = Val(GetEnvironmentVariable("CONTENT_LENGTH"))
cgi\ContentType = GetEnvironmentVariable("CONTENT_TYPE")
cgi\DocumentRoot = GetEnvironmentVariable("DOCUMENT_ROOT")
cgi\GatewayInterface = GetEnvironmentVariable("GATEWAY_INTERFACE")
cgi\PathInfo = GetEnvironmentVariable("PATH_INFO")
cgi\PathTranslated = GetEnvironmentVariable("PATH_TRANSLATED")
cgi\QueryString = GetEnvironmentVariable("QUERY_STRING")
cgi\RemoteAddr = GetEnvironmentVariable("REMOTE_ADDR")
cgi\RemoteHost = GetEnvironmentVariable("REMOTE_HOST")
cgi\RemoteIdent = GetEnvironmentVariable("REMOTE_IDENT")
cgi\RemotePort = GetEnvironmentVariable("REMOTE_PORT")
cgi\RemoteUser = GetEnvironmentVariable("REMOTE_USER")
cgi\RequestURI = GetEnvironmentVariable("REQUEST_URI")
cgi\RequestMethod = GetEnvironmentVariable("REQUEST_METHOD")
cgi\ScriptName = GetEnvironmentVariable("SCRIPT_NAME")
cgi\ScriptFilename = GetEnvironmentVariable("SCRIPT_FILENAME")
cgi\ServerAdmin = GetEnvironmentVariable("SERVER_ADMIN")
cgi\ServerName = GetEnvironmentVariable("SERVER_NAME")
cgi\ServerPort = GetEnvironmentVariable("SERVER_PORT")
cgi\ServerProtocol = GetEnvironmentVariable("SERVER_PROTOCOL")
cgi\ServerSignature = GetEnvironmentVariable("SERVER_SIGNATURE")
cgi\ServerSoftware = GetEnvironmentVariable("SERVER_SOFTWARE")
cgi\HTTPAccept = GetEnvironmentVariable("HTTP_ACCEPT")
cgi\HTTPAcceptEncoding = GetEnvironmentVariable("HTTP_ACCEPT_ENCODING")
cgi\HTTPAcceptLanguage = GetEnvironmentVariable("HTTP_ACCEPT_LANGUAGE")
cgi\HTTPCookie = GetEnvironmentVariable("HTTP_COOKIE")
cgi\HTTPForwarded = GetEnvironmentVariable("HTTP_FORWARDED")
cgi\HTTPHost = GetEnvironmentVariable("HTTP_HOST")
cgi\HTTPPragma = GetEnvironmentVariable("HTTP_PRAGMA")
cgi\HTTPReferer = GetEnvironmentVariable("HTTP_REFERER")
cgi\HTTPUserAgent = GetEnvironmentVariable("HTTP_USER_AGENT")
; -------------------------------------------------------
; now to get cgi POST data, if any
If cgi\ContentLength>0
*Buffer = AllocateMemory(cgi\ContentLength)
hInput = GetStdHandle_(#STD_INPUT_HANDLE)
;SetConsoleMode_(hInput, #ENABLE_LINE_INPUT|#ENABLE_ECHO_INPUT|#ENABLE_PROCESSED_INPUT)
ReadFile_(hInput, *Buffer, cgi\ContentLength, @bRead, 0)
cgi\PostData = PeekS(*Buffer)
FreeMemory(*Buffer)
CloseHandle_(hInput)
EndIf
EndProcedure
; RESPONSE PROCEDURES
Macro CGI_Reply(response)
OpenConsole()
Written = WriteConsoleData(response,MemoryStringLength(response))
CloseConsole()
EndMacro
Procedure ReplyLocation(URLorFilename.s)
; this is for redirecting, or sending a file back as response
header.s = "Location: "+URLorFilename + #CRLF$ + #CRLF$
CGI_Reply(@header)
EndProcedure
Procedure ReplyText(string.s)
HttpAnswer.s = "Content-type: text/plain;charset=UTF-8" + #CRLF$ + #CRLF$ + string
CGI_Reply(@HttpAnswer)
EndProcedure
Procedure ReplyHTML(html.s)
HttpAnswer.s = "Content-type: text/html;charset=UTF-8" + #CRLF$ + #CRLF$ + html
CGI_Reply(@HttpAnswer)
EndProcedure
Procedure.b ReplyImage(image.i,format.i)
; this is for sending a native PB image to fill an IMG element
; the respective image encoder will be needed depending on the format used
; eg. if you're sending the image as a PNG, make sure you have called UsePNGImageEncoder() somewhere
If Not IsImage(image)
ProcedureReturn #False
EndIf
contenttype.s
Select format
Case #PB_ImagePlugin_BMP
contenttype = "x-ms-bmp"
Case #PB_ImagePlugin_JPEG ; remember to call UseJPEGImageEncoder()
contenttype = "jpeg"
Case #PB_ImagePlugin_JPEG2000 ; remember to call UseJPEG2000ImageEncoder()
contenttype = "jp2"
Case #PB_ImagePlugin_PNG ; remember to call UsePNGImageEncoder()
contenttype = "x-png"
EndSelect
slaveimgfile.s = "C:\slaveimgfile.tmp"
SaveImage(image,slaveimgfile,format)
; read data back in
file = ReadFile(#PB_Any,slaveimgfile)
If Not file
ProcedureReturn #False
EndIf
idlength = Lof(file)
*image = AllocateMemory(idlength)
bytes = ReadData(file,*image,idlength)
CloseFile(file)
DeleteFile(slaveimgfile)
; form response header
header.s = "Content-type: image/"+contenttype + #CRLF$ + #CRLF$
OpenConsole()
Written1=WriteConsoleData(@header,Len(header))
Written2=WriteConsoleData(*image,idlength)
CloseConsole()
FreeMemory(*image)
ProcedureReturn #True
EndProcedure
Procedure.b ReplyImageFile(filename.s,format.i)
; this is for sending the contents of an image file (.jpg etc) back to fill an IMG element
; no encoders or decoders are necessary since we are simply sending the file's raw data
; however, denote the format using #PB_ImagePlugin_[FORMAT] so that the procedure knows which content-type the data should be sent with
If FileSize(filename)<0
ProcedureReturn #False
EndIf
contenttype.s
Select format
Case #PB_ImagePlugin_BMP
contenttype = "x-ms-bmp"
Case #PB_ImagePlugin_JPEG
contenttype = "jpeg"
Case #PB_ImagePlugin_JPEG2000
contenttype = "jp2"
Case #PB_ImagePlugin_PNG
contenttype = "x-png"
EndSelect
; read data back in
file = ReadFile(#PB_Any,filename)
If Not file
ProcedureReturn #False
EndIf
idlength = Lof(file)
*image = AllocateMemory(idlength)
bytes = ReadData(file,*image,idlength)
CloseFile(file)
; form response header
header.s = "Content-type: image/"+contenttype + #CRLF$ + #CRLF$
OpenConsole()
Written1=WriteConsoleData(@header,Len(header))
Written2=WriteConsoleData(*image,idlength)
CloseConsole()
FreeMemory(*image)
ProcedureReturn #True
EndProcedure
GetCGIVariables()
;-
;- PROGRAM START
; start here
; any request data will probably be in the cgi\PostData string
; but this demo ignores the request and simply sends back an image
; do it from file...
;ReplyImageFile("C:\Image018.jpg",#PB_ImagePlugin_JPEG) : End
; do it with a native PB image...
iw = 300
ih = 225
img = CreateImage(#PB_Any,iw,ih)
StartDrawing(ImageOutput(img))
Box(0,0,iw,ih,RGB(0,0,64))
margin=1
For a = 1 To 33
level = Random(255)
LineXY(margin+Random(iw-margin-margin),margin+Random(ih-margin-margin),margin+Random(iw-margin-margin),margin+Random(ih-margin-margin),RGB(level,level,level))
Next a
DrawText(10,10," Hello from PB ",#Black,#Yellow)
StopDrawing()
UseJPEGImageEncoder()
ReplyImage(img,#PB_ImagePlugin_JPEG)
FreeImage(img)
Then save this as an HTML file in your local server folder:
Code: Select all
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<TITLE>IMG test</TITLE>
</head>
<body>
<IMG src="pb.exe">
</body>
</html>
I think other content types could be handled in a similar way, but as yet I've had no need of them so haven't accommodated them yet.
As for XAMPP, I've been using it for years to build websites offline. I can't remember the settings. I'll examine my conf files and post back if I can work out what is necessary to make it work. From what I remember, my difficulty with XAMPP was getting it to work in the first place (folders etc.) - after that, getting it to work with PB executables was easy.
As to the PB code, everything up till the line
Code: Select all
;- PROGRAM START
I am currently using this code as the basis for a fairly complex Ajax framework. It's done very simply: the cgi\PostData is stringfielded to get all the "aspects" of a completely custom request. A reply is then formulated and sent back with similar dressing to a JavaScript system at the client end.
Obviously it can also handle Sjax requests.
Or you can use it as simply as in the demo. But to be honest I hate CGI pages; Ajax is a far more sensible way to do things.
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
Re: CGI Survival Guide
You should call OpenConsole() only once (and never closeconsole()). Nice framework.
- greyhoundcode
- Enthusiast
- Posts: 112
- Joined: Sun Dec 30, 2007 7:24 pm
Re: CGI Survival Guide
Nice piece of work.
-
- Addict
- Posts: 1264
- Joined: Wed Feb 28, 2007 9:13 am
- Location: London
Re: CGI Survival Guide
Thank you both for the compliments. I'm always nervous about posting code in case it turns out to be rubbish. 

JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
Re: CGI Survival Guide
Oh, don't worry about it, it has never stopped me beforeSeymour Clufley wrote: Thank you both for the compliments. I'm always nervous about posting code in case it turns out to be rubbish.![]()

( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
( The path to enlightenment and the PureBasic Survival Guide right here... )
- greyhoundcode
- Enthusiast
- Posts: 112
- Joined: Sun Dec 30, 2007 7:24 pm
ISAPI or CGI
What about compiling to a DLL, to run our web apps ISAPI style, with a view to further speed improvements over a CGI executable? So that it remains loaded in the server memory rather than a new process being spawned each time a visitor makes an HTTP request, I mean.
- DoubleDutch
- Addict
- Posts: 3220
- Joined: Thu Aug 07, 2003 7:01 pm
- Location: United Kingdom
- Contact:
Re: CGI Survival Guide
Thats a really good idea.
Does anyone know if Linux have an equivalent system to DLL's as my host uses Linux?
Does anyone know if Linux have an equivalent system to DLL's as my host uses Linux?
https://deluxepixel.com <- My Business website
https://reportcomplete.com <- School end of term reports system
https://reportcomplete.com <- School end of term reports system
Re: ISAPI or CGI
What you describing sounds almost exactly like FastCGI. It's built into the server but not all servers have this feature. Also, your cgi's have to be written as a FastCGI program. Someone on here did one but I don't remember who. I would like to learn how to do this as well. This site has some good explanation.greyhoundcode wrote:What about compiling to a DLL, to run our web apps ISAPI style, with a view to further speed improvements over a CGI executable? So that it remains loaded in the server memory rather than a new process being spawned each time a visitor makes an HTTP request, I mean.
http://cryp.to/publications/fastcgi/
Make everything as simple as possible, but not simpler. ~Albert Einstein
-
- Addict
- Posts: 1264
- Joined: Wed Feb 28, 2007 9:13 am
- Location: London
Re: CGI Survival Guide
I've also been looking for a solution to this problem. And it really is a problem if a lot of data needs to be known by the CGI program. (The data for my current website takes almost a minute to load into a program!)So that it remains loaded in the server memory rather than a new process being spawned each time a visitor makes an HTTP request
What I've been doing is have a separate program which is always running. This communicates with "the CGI program" by means of temporary files. The CGI program is just a go-between, which writes the request info to a file with a unique code (4983986.request). The "permanent" program scans the folder for new files, and responds to each one by creating a "response" file with the same code (4983986.response). The CGI program has been waiting for such a file to appear and when it does, the program reads it in and sends the contents back to the client, then terminates itself.
This does solve the problem and response time is actually fast. But there must be better ways for two programs to communicate than using temporary files.
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
- greyhoundcode
- Enthusiast
- Posts: 112
- Joined: Sun Dec 30, 2007 7:24 pm
Re: CGI Survival Guide
I wonder if environmental variables could help? Though probably FastCGI or ISAPI would be the perfect answer. I suppose the problem is that this is all quite specialised stuff ... surely someone will have an answer!
Re: CGI Survival Guide
Hi all,
This thread happens to fall in line with what I am doing myself. Granted I'm just starting write a CGI handler but thats where I have to start from. I find though if you read a few RFCs this is not a complicated task. I've built a handler for CGI with relatively little effort. FastCGI, is something I want to try next. I'm more than happy to share any code I might create. My other aim is to make things cross platform since I require code that works in such a fashion. Its interesting so far to see how much smaller what I've written is then what has been posted. In any case I intend to write this up and post everything. I'll include everything I can and link it. My code is also completely purebasic. Post more when I'm done.
This thread happens to fall in line with what I am doing myself. Granted I'm just starting write a CGI handler but thats where I have to start from. I find though if you read a few RFCs this is not a complicated task. I've built a handler for CGI with relatively little effort. FastCGI, is something I want to try next. I'm more than happy to share any code I might create. My other aim is to make things cross platform since I require code that works in such a fashion. Its interesting so far to see how much smaller what I've written is then what has been posted. In any case I intend to write this up and post everything. I'll include everything I can and link it. My code is also completely purebasic. Post more when I'm done.
Last edited by kake26 on Thu Jan 28, 2010 9:21 am, edited 1 time in total.
-
- Addict
- Posts: 1264
- Joined: Wed Feb 28, 2007 9:13 am
- Location: London
Re: CGI Survival Guide
Kake26, I for one would be interested in PB code for FastCGI.
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."