[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. [CMcC] 20040805 - this bit below is troubling and probably not necessary. If you [[lappend Cgi(env-pass) REDIRECT_STATUS]] and set REDIRECT_STATUS to 1 before you start tclhttpd server process, then your variable will be passed to the cgi. Could you please test if that works, and if so, remove this code below? If you need to, you could set/unset ::env(REDIRECT_STATUS) within the mime type scripts. I've put a suggested implementation below the original code ... someone try it out please? ---- 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" * the example above can only work under Unix, because Windows needs to be told which interpreter (In this case $Cgi(php) to run over files with .php extensions. There's a three line patch to cgi.tcl, below. ---- For Windows only: cgi.tcl line 372 (inside the switch): .php { return [open "|[list $Cgi(php) $script] $arglist" r+] } ---- [CMcC] here's what I was suggesting - put this in custom, and don't modify cgi.tcl, does this give the desired results? If it does, please remove the above ... unnecessary modification of cgi.tcl gives me dyspepsia. ##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 lappend Cgi(env-pass) REDIRECT_STATUS proc Doc_application/x-php {path suffix sock} { upvar #0 Httpd$sock data set ::env(REDIRECT_STATUS) 1 Url_Handle [list CgiHandle $data(url) {} $path] $sock unset ::env(REDIRECT_STATUS) } proc Doc_application/x-php {path suffix sock} { upvar #0 Httpd$sock data set ::env(REDIRECT_STATUS) 1 Url_Handle [list CgiHandle $data(url) {} $path] $sock unset ::env(REDIRECT_STATUS) } puts "PHP CGI Stuff loaded" puts {You need to register your php cgi directories with Cgi_Directory} ---- [LES] on 20040929: it does not work for me on Windows 98. I click my '''index.php''' file and only get its content in plain text. Will try Linux later... :-( Les, did the original posted version work for you? I wonder whether that bit about registering your php directory as a Cgi directory might make a difference. -- [CMcC] [LES] After a [Tcl Chatroom] session, [CMcC] came up with the solution. So the two code snippets above make [PHP] work with [Tclhttpd]. [CMcC] it exposes a problem with [Tclhttpd] under Windows, though, which is that cgi processing has hard-coded mapping from extension to interpreter. Really, it should be more flexible. I'll submit an RFE so we remember that something could be done, but I'm not going to do the work, because I don't use Windows and hardly ever use CGI. ---- [schlenk] On Windows the following worked: Setting up PHP: * Download the PHP binaries for windows from http://www.php.net/downloads.php * Unzip the zip file in c:/php * Copy the c:/php.ini-recommended file to c:/php/php.ini * Edit the php.ini file and set the doc_root to your tclhttpd doc_root Setting up Tclhttp: * Add the cgi.tcl fix from above to tclhttp/lib/cgi.tcl * Save the following script to tclhttp/custom/php.tcl ##Add the mime types Mtype_Add php application/x-php Mtype_Add php3 application/x-php Mtype_Add phtml application/x-php ###Edit this your path, Win used to need full path; now it seems not to set Cgi(php) "c:/php/php-cgi.exe" ;# For .php #set Cgi(php) "php" ;# For .php lappend Cgi(env-pass) REDIRECT_STATUS proc Doc_application/x-php {path suffix sock} { upvar #0 Httpd$sock data set ::env(REDIRECT_STATUS) 1 Url_Handle [list CgiHandle $data(url) {} $path] $sock unset ::env(REDIRECT_STATUS) } puts "PHP CGI Support loaded" * Place this example script in tclhttp/htdocs/phptest.php * Start Tclhttpd an point the browser to your the phptest.php file... ---- [zbang] On *nix, in addition to the custom code above, I had to modify lib/tclhttpd3.5.1/cgi.tcl so that it would actually use the Cgi array. proc CgiExec {script arglist} { global tcl_platform global Cgi set prog "" set extn [string trim [file extension $script] "."] if { $extn != "cgi" } { if { [info exists Cgi($extn)] } { set prog "$Cgi($extn) " } } switch -- $tcl_platform(platform) { unix { if {[file exists /dev/stdout]} { # This trick "2> /dev/stdout" fails if you start the process in # the background under an xterm, then quit the xterm. In that case # the open raises an error. if { ! [catch {open "|$prog[list $script] $arglist 2> /dev/stdout" r+} pipe]} { return $pipe } } # We use cat to merge the stderr and stdout return [open "|$prog[list $script] $arglist |& cat" r+] } I didn't try this on windows, but it might be more correct to change the windows section to use the $prog variable, too. A couple of other things: If you register the directory containing the php scripts as a cgi dir with Cgi_Directory, it appears that the Doc_application/x-php proc won't be called at all. It's not clear whether the file extensions as registered with Mtype_Add should have a leading period. It looks like they should, based on what's in the MimeType array. There is code in a number of places to remove that period if present. ---- 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] ]]