[NB] On several occasions, I've had the need to run/use some useful [php] (no-flames..) apps/scripts, but did not want to install a full-blown [Apache] distro...., much prefering to use tclhttpd;-) With these hacks below, PHP seems to work as a [cgi] under [TclHttpd]. Edit cgi.tcl in the lib directory.., specifically CgiSpawn and CgiClose, essentially setting/unsetting env(REDIRECT_STATUS). This is needed so PHP does not complain about security breach and stop execution. ---- proc CgiSpawn {sock script} { upvar #0 Httpd$sock data global env Cgi ##Nikos:This env var is needed to run php cgi securely, in directories under docroot set env(REDIRECT_STATUS) 1 if {$Cgi(cgi) >= $Cgi(maxcgi)} { Httpd_Error $sock 504 "Too many CGI's" return } incr Cgi(cgi) # for GET queries, pass the query as an argument to the cgi script if {$data(proto) == "POST"} { set arglist "" } else { set arglist $data(query) } set pwd [pwd] cd [file dirname $script] if {[catch {CgiExec $script $arglist} fd]} { cd $pwd Httpd_Error $sock 400 $fd incr Cgi(cgi) -1 return } cd $pwd Count cgihits set data(infile) $fd ;# So close happens in Httpd_SockClose set data(header) 0 ;# Have not read header yet set data(headerlist) {} ;# list of read headers set data(headercode) "200 data follows" ;# normal return fconfigure $fd -blocking 0 # Set up a timer in case it hangs catch {after cancel $data(cancel)} set data(cancel) [after $Cgi(timeout) CgiCancel $fd $sock] if {$data(proto) == "POST"} { fconfigure $fd -translation binary if {$data(count) == 0} { # Either there was no POST data, or we are inside a domain # that automatically read the POST data into data(query) already # Errors appear here because of the non-blocking writes. catch { puts -nonewline $fd $data(query) flush $fd } } else { # Pump the query data to the CGI process in the background # We set up fileevents after this finishes, so return now # fcopy bug in Tcl 8.3.2 and Tcl 8.4a2 and all previous versions # prevents this from working reliably on large amounts of POST data # fcopy $sock $fd -command [list CgiCopyDone $sock $fd] -size $data(count) fileevent $sock readable [list CgiCopyPost $sock $fd] return } } CgiCopyDone $sock $fd $data(count) "" } ---- proc CgiClose {fd sock {bytes {}} {error {}}} { global Cgi upvar #0 Httpd$sock data catch {after cancel $data(cancel)} incr Cgi(cgi) -1 ##Nikos:This env var was needed to run php cgi securely, now we unset it.. catch {unset ::env(REDIRECT_STATUS)} if {![info exists data(header)]} { Httpd_Error $sock 204 } else { Httpd_SockClose $sock 1 } if {[string length $error] > 0} { Log $sock CgiClose $error } } [glennj]: you unser your env.var whether or not data(header) exists, so instead of doing it in 3 places, why don't you pull it out of the if blocks and place it after your incr call? ---- [NB] Done... ---- Add this to the custom directory ---- ###Nikos:Hack to add php cgi capabilities into tclhttpd... ##Add the mime types Mtype_Add application/x-php .php Mtype_Add application/x-php .php3 Mtype_Add application/x-php .phtml ###Edit this your path, Win used to need full path; now it seems not to #set Cgi(php) "c:/php/php.exe" ;# For .php set Cgi(php) "php" ;# For .php proc Doc_application/x-php {path suffix sock} { upvar #0 Httpd$sock data Url_Handle [list CgiHandle $data(url) {} $path] $sock } proc Doc_application/x-php {path suffix sock} { upvar #0 Httpd$sock data Url_Handle [list CgiHandle $data(url) {} $path] $sock } puts "PHP CGI Stuff loaded" puts {You need to register your php cgi directories with Cgi_Directory} ---- Caveats: * There's probably a better point to hook this into the cgi library, but at least this'll get someone started * If php-dir is outside the docroot (which, I think is a no-no for cgi), and is registered as a virtual directory, then PHP complains of "No Input File" ---- Another way to achieve the same thing would be to scatter some random delays in the Tcl code. ---- See also [PHP] and [Tclhttpd] [[ [Category TclHttpd] ]]