Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

TCL as CGI script

87 views
Skip to first unread message

VuDuCh|ld

unread,
Jul 23, 1998, 3:00:00 AM7/23/98
to
I am trying to use a tcl script to except a POST from a form and parse
the contents, then write it to a file. I can run it from tclsh manually
and it seems to work fine. I have tested the form to make sure of the
values that its posting and it appears to be fine also. However, when I
try to make them work together as they should, I get a generic 'internal
server error' message. This is my first attempt at cgi ever so im not
sure even where to begin. The script is below and is called with the
named values 'Nick=whatever' and 'Message=whatever' from the form. It
should then write this information to an existing file called
messages.www. Anybody got any pointers?

#!/usr/bin/tclsh
set parsed_list "[split $argv &]"
set nick [lindex [split [lindex $parsed_list 0] =] 1]
set message [lrange [split [lindex $parsed_list 1] =] 1 end]
set file [open /home/vewdew/html/messages.www a]
puts $file "$nick $message"
close $file
puts "Location: /home/vewdew/html/eaug/message.html"
puts ""


Jean-Yves Terrien

unread,
Jul 24, 1998, 3:00:00 AM7/24/98
to
Hi
an cgi program don't get param with argc argv there are passed to the
script in global variable
env(CONTENT_TYPE)
env(REQUEST_METHOD)
env(QUERY_STRING) #content the passed parameter string
env(CONTENT_LENGTH)
etc.

if you want write cgi with tcl you can get the cgi package
The cgi.tcl home page is http://expect.nist.gov/cgi.tcl
this package content all necessary for get et parse the query_string and
all for write html with tcl.

bye JYT
PS: sorry for my approximative english


Cherno

unread,
Jul 24, 1998, 3:00:00 AM7/24/98
to VuDuCh|ld

On Thu, 23 Jul 1998, VuDuCh|ld wrote:
[...]
// #!/usr/bin/tclsh
// set parsed_list "[split $argv &]"
// set nick [lindex [split [lindex $parsed_list 0] =] 1]
// set message [lrange [split [lindex $parsed_list 1] =] 1 end]
// set file [open /home/vewdew/html/messages.www a]
// puts $file "$nick $message"
// close $file
// puts "Location: /home/vewdew/html/eaug/message.html"
// puts ""

Output the mime type of the file before the location:

puts "Content-type: text/html"
puts "Location: /home/vewdew/html/eaug/message.html\n"

If you're running apache, you can check out the httpd-error.log
file and it might give a hint as to what is going on.

Hope that helped,
Cherno.


VuDuCh|ld

unread,
Jul 24, 1998, 3:00:00 AM7/24/98
to jeanyves...@cnet.francetelecom.fr
I was under the impression that it depended on the method you used in the
form. I am using POST submission and not GETS. GETS should use the
envirnonment varibails if I understood the documentation correctly. POST
should allow the script to read it from STDIN. Is this incorrect?

kam

unread,
Jul 26, 1998, 3:00:00 AM7/26/98
to
What version of Tcl are you using?
In Tcl 7.3 you could use the following to get the results from a POST
action, this is like a "Hello World", the very basics, be aware that the
SPACE
after the puts "Contents-type/html is mandatory.

#! /usr/local/bin/tcl_cgi

cgi_parse_query [cgi_get_query] Q

puts "Content-type: text/html

<TITLE>Query Response</TITLE>
<H1>Query Response</H1>

Your name is <B>$Q(username)</B>
<P>
Your sent your query from <B>$env(REMOTE_HOST)</B>."

Here's the HTML to call this in 7.3, this is a snippet:

<!--Windows NT-->
<FORM METHOD="POST" ACTION="cgi-bin/tclsh.exe?simple.tcl">
<!--UNIX-->
<!FORM METHOD="POST" ACTION="/cgi-bin/tclsh.exe?simple.tcl">
Type your name: <INPUT TYPE="text" NAME="username">
<P>
<INPUT TYPE="submit" VALUE="send query">
</FORM>

We've just upgrade to Tcl80p2 and this is now broken. It appears that the
function
has changed and is now supported via built-in utility: HTTP.

Here's the example from the on-line help:

EXAMPLE

# Copy a URL to a file and print meta-data
proc ::http::copy { url file {chunk 4096} } {
set out [open $file w]
set token [geturl $url -channel $out -progress ::http::Progress \
-blocksize $chunk]
close $out
# This ends the line started by http::Progress
puts stderr ""
upvar #0 $token state
set max 0
foreach {name value} $state(meta) {
if {[string length $name] > $max} {
set max [string length $name]
}
if {[regexp -nocase ^location$ $name]} {
# Handle URL redirects
puts stderr "Location:$value"
return [copy [string trim $value] $file $chunk]
}
}
incr max
foreach {name value} $state(meta) {
puts [format "%-*s %s" $max $name: $value]
}

return $token
}
proc ::http::Progress {args} {
puts -nonewline stderr . ; flush stderr
}

When we run this we get the following error:

CGI Error

The specified CGI application misbehaved by not returning a complete set of
HTTP headers. The headers it did return are:

can't create procedure "::http::copy": unknown namespace
while executing
"proc ::http::copy { url file {chunk 4096} } {
set out [open $file w]
set token [geturl $url -channel $out -progress ::http::Progress \
-block..."
(file "C:\InetPub\scripts\tcl80p2_example.tcl" line 2)

Anyone has a code snippet that takes a User's name from a Form and Prints it
and the IP address, like the example at the top?

Regards,

VuDuCh|ld wrote:

> I am trying to use a tcl script to except a POST from a form and parse
> the contents, then write it to a file. I can run it from tclsh manually
> and it seems to work fine. I have tested the form to make sure of the
> values that its posting and it appears to be fine also. However, when I
> try to make them work together as they should, I get a generic 'internal
> server error' message. This is my first attempt at cgi ever so im not
> sure even where to begin. The script is below and is called with the
> named values 'Nick=whatever' and 'Message=whatever' from the form. It
> should then write this information to an existing file called
> messages.www. Anybody got any pointers?
>
> #!/usr/bin/tclsh

> set parsed_list "[split $argv &]"

> set nick [lindex [split [lindex $parsed_list 0] =] 1]

> set message [lrange [split [lindex $parsed_list 1] =] 1 end]

> set file [open /home/vewdew/html/messages.www a]

Le NETtoyeur

unread,
Jul 28, 1998, 3:00:00 AM7/28/98
to
VuDuCh|ld <vew...@tclslave.net> a écrit dans l'article
<35B7BB2F...@tclslave.net>...

> I am trying to use a tcl script to except a POST from a form and parse
> the contents, then write it to a file. I can run it from tclsh manually
> and it seems to work fine. I have tested the form to make sure of the
> values that its posting and it appears to be fine also. However, when I
> try to make them work together as they should, I get a generic 'internal
> server error' message. This is my first attempt at cgi ever so im not
> sure even where to begin. The script is below and is called with the
> named values 'Nick=whatever' and 'Message=whatever' from the form. It
> should then write this information to an existing file called
> messages.www. Anybody got any pointers?
>
> #!/usr/bin/tclsh
> set parsed_list "[split $argv &]"
> set nick [lindex [split [lindex $parsed_list 0] =] 1]
> set message [lrange [split [lindex $parsed_list 1] =] 1 end]
> set file [open /home/vewdew/html/messages.www a]
> puts $file "$nick $message"
> close $file
> puts "Location: /home/vewdew/html/eaug/message.html"
> puts ""

Parameters passing via a form to cgi program is different between
GET and POST method. Your code can work only with the GET
method. Normally, that's not the way for unescaping parameters
(via argv). Here are the functions that I used in my cgi scripts:

#cgilib.tcl
proc Cgi_Parse {} {
global env cgi query
if {![info exists env(QUERY_STRING)] ||
[string length $env(QUERY_STRING)] == 0} {
if [info exists env(CONTENT_LENGTH)] {
set query [read stdin $env(CONTENT_LENGTH)]
} else {
gets stdin query
}
} else {
set query $env(QUERY_STRING)
}
regsub -all {\+} $query { } query
foreach {name value} [split $query &=] {
if [info exists list($name)] {
set cgi($name) [list $cgi($name) [CgiDecode $value]]
unset list($name)
} elseif [info exists cgi($name)] {
lappend cgi($name) [CgiDecode $value]
} else {
set cgi($name) [CgiDecode $value]
set list($name) 1 ;# Need to listify if more values are added
}
}
return [array names cgi]
}
proc CgiDecode {str} {
# Protect Tcl special chars
regsub -all {[][\\\$]} $str {\\&} str
# Replace %xx sequences with a format command
regsub -all {%([0-9a-fA-F][0-9a-fA-F])} $str {[format %c 0x\1]} str
# Replace the format commands with their result
return [subst $str]
}

In the main program:

#!/usr/local/bin/tclsh
source cgilib.tcl
Cgi_Parse
#Then, all the parameters are in the $cgi array.

For more information about cgi programming, visit this URL:

http://www.cgi-resources.com/Documentation/CGI_Tutorials/

Le /\/ETtoyeur
NETt...@france-mail.com
"Le sexe est une faculté qui rétrécit"


Le NETtoyeur

unread,
Jul 28, 1998, 3:00:00 AM7/28/98
to
Cherno <cja...@ipv6-1.ee.tuns.ca> a écrit dans l'article
<Pine.BSF.3.96.98072...@ipv6-1.ee.tuns.ca>...

I'd prefered:
puts "Content-type: text/plain \n"

for debugging purpose only. Because, the "Location:" header should not
be preceded by any other headers. Otherwise, it won't work.

Rob Szarek

unread,
Aug 4, 1998, 3:00:00 AM8/4/98
to
VuDuCh|ld wrote:
>
> I am trying to use a tcl script to except a POST from a form and parse
> the contents, then write it to a file. I can run it from tclsh manually
> and it seems to work fine. I have tested the form to make sure of the
> values that its posting and it appears to be fine also. However, when I
> try to make them work together as they should, I get a generic 'internal
> server error' message. This is my first attempt at cgi ever so im not
> sure even where to begin. The script is below and is called with the
> named values 'Nick=whatever' and 'Message=whatever' from the form. It
> should then write this information to an existing file called
> messages.www. Anybody got any pointers?
>
> #!/usr/bin/tclsh
> set parsed_list "[split $argv &]"
> set nick [lindex [split [lindex $parsed_list 0] =] 1]
> set message [lrange [split [lindex $parsed_list 1] =] 1 end]
> set file [open /home/vewdew/html/messages.www a]
> puts $file "$nick $message"
> close $file
> puts "Location: /home/vewdew/html/eaug/message.html"
> puts ""

If you want a quick and dirty way, and you're using Unix:

puts "Content-Type: text/plain\n"
set inData [split [gets stdin] &]

for {set indx 0} {$indx < [llength $inData]} {incr indx} {
set item [lindex $inData $indx]
set inVar [lindex [split $item =] 0]
set inVal [lindex [split $item =] 1]
set form($inVar) $inVal
}

# Code for writing to a file to follow

HTML form data will then be stored in an array "form" with the
variable name as the array index.

Caveat:

You'll need to modify this code if you want proper handling of
select lists since they use the same variables in a cgi post. Also
you'll need to regsub -all "+" symbols to get back any spaces you need
from the strings.

0 new messages