Version 1 of PHP under Tclhttpd

Updated 2004-08-02 06:26:25

NB On several occassions, 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
    if {![info exists data(header)]} {
        ##Nikos:This env var was needed to run php cgi securely, now we unset it..
        catch {unset env(REDIRECT_STATUS)}
        Httpd_Error $sock 204
    } else {
        Httpd_SockClose $sock 1
        ##Nikos:This env var was needed to run php cgi securely, now we unset it..
        catch {unset env(REDIRECT_STATUS)}
    }
    if {[string length $error] > 0} {
        Log $sock CgiClose $error
        ##Nikos:This env var was needed to run php cgi securely, now we unset it..
        catch {unset env(REDIRECT_STATUS)}
    }

 }

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"

See also PHP and Tclhttpd

[ Category TclHttpd ]