joosters                Mon Mar 19 03:03:29 2001 EDT

  Added files:                 
    /php4/sapi/fastcgi  CREDITS Makefile.in README.FastCGI config.m4 
                        fastcgi.c php.sym php_fastcgi.h 

  Modified files:              
    /php4       Makefile.in configure.in 
  Log:
  @ New FastCGI server module
  New FastCGI server module. Based on the thttpd server module with
  large chunks of code ripped from the cgi module. Also modifies
  Makefile.in and configure.in in order to make it build properly.
  # This initial checkin has been tested with the Zeus web server,
  # but should work with any server that has a correct FastCGI
  # implementation.
  
  
Index: php4/Makefile.in
diff -u php4/Makefile.in:1.95 php4/Makefile.in:1.96
--- php4/Makefile.in:1.95       Sun Jun 11 11:51:17 2000
+++ php4/Makefile.in    Mon Mar 19 03:03:29 2001
@@ -18,7 +18,7 @@
 
 PROGRAM_NAME         = php
 PROGRAM_SOURCES      = stub.c
-PROGRAM_LDADD        = libphp4.la
+PROGRAM_LDADD        = libphp4.la $(EXT_PROGRAM_LDADD)
 PROGRAM_LDFLAGS      = -export-dynamic 
 PROGRAM_DEPENDENCIES = $(PROGRAM_LDADD)
 
Index: php4/configure.in
diff -u php4/configure.in:1.222 php4/configure.in:1.223
--- php4/configure.in:1.222     Thu Mar 15 23:13:06 2001
+++ php4/configure.in   Mon Mar 19 03:03:29 2001
@@ -1,4 +1,4 @@
-dnl ## $Id: configure.in,v 1.222 2001/03/16 07:13:06 sniper Exp $ -*- sh -*-
+dnl ## $Id: configure.in,v 1.223 2001/03/19 11:03:29 joosters Exp $ -*- sh -*-
 dnl ## Process this file with autoconf to produce a configure script.
 
 divert(1)
@@ -644,6 +644,11 @@
 if test "$PHP_SAPI" = "cgi"; then
   PHP_PROGRAM=php
 fi
+
+if test "$PHP_SAPI" = "fastcgi"; then
+  PHP_PROGRAM=php
+fi
+
 
 PHP_REGEX
 

Index: php4/sapi/fastcgi/Makefile.in
+++ php4/sapi/fastcgi/Makefile.in

LTLIBRARY_NAME    = libsapi.la
LTLIBRARY_SOURCES = fastcgi.c

include $(top_srcdir)/build/ltlib.mk

Index: php4/sapi/fastcgi/README.FastCGI
+++ php4/sapi/fastcgi/README.FastCGI
FastCGI module
--------------

This module requires the FastCGI development kit, available from
http://www.fastcgi.com/

Before building PHP, please enter the dev kit, and run:

/configure
make
make export

This will compile the library code required for the FastCGI module. All
that is then required is to configure PHP with the '--with-fastcgi' option.
After making the code, you will end up with a binary file called 'php'.
Installation of this file will depend on the web server being used, please
see their documentation for details.

Index: php4/sapi/fastcgi/config.m4
+++ php4/sapi/fastcgi/config.m4
AC_MSG_CHECKING(for FastCGI support)
AC_ARG_WITH(fastcgi,
[  --with-fastcgi=SRCDIR   Build PHP as FastCGI application],[
  if test "$withval" = "yes"; then
        FASTCGIPATH=/usr/local
  else
        FASTCGIPATH=$withval
  fi
  test -f "$FASTCGIPATH/lib/libfcgi.a" || AC_MSG_ERROR(Unable to find libfcgi.a in 
$FASTCGIPATH/lib)
  test -f "$FASTCGIPATH/include/fastcgi.h" || AC_MSG_ERROR(Unable to find fastcgi.h in 
$FASTCGIPATH/include)
  PHP_SAPI=fastcgi
  PHP_LIBS=$FASTCGIPATH/lib/libfcgi.a
  AC_ADD_INCLUDE($FASTCGIPATH/include)
  EXT_PROGRAM_LDADD="$EXT_PROGRAM_LDADD $FASTCGIPATH/lib/libfcgi.a"
  INSTALL_IT="\$(INSTALL) -m 0755 $SAPI_PROGRAM \$(bindir)/$SAPI_FASTCGI"
  RESULT="yes"
  PHP_SUBST(FASTCGI_LIBADD)
  PHP_SUBST(EXT_PROGRAM_LDADD)
],[
  RESULT="no"
])
AC_MSG_RESULT($RESULT)

Index: php4/sapi/fastcgi/fastcgi.c
+++ php4/sapi/fastcgi/fastcgi.c
/*
   +----------------------------------------------------------------------+
   | PHP version 4.0                                                      |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2001 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 2.02 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available at through the world-wide-web at                           |
   | http://www.php.net/license/2_02.txt.                                 |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Ben Mansell <[EMAIL PROTECTED]>                            |
   +----------------------------------------------------------------------+
*/

/* Debugging */
/* #define DEBUG_FASTCGI 1 */

/* Two configurables for the FastCGI runner.
 *
 * PHP_FCGI_CHILDREN - if set, the FastCGI will pre-fork this many processes
 *                     which will accept requests.
 *
 * PHP_FCGI_MAX_REQUESTS - if set, the runner will kill itself after handling
 *                         the given number of requests. This is to curb any
 *                         memory leaks in PHP.
 */


/* The following code is based mainly on the thttpd sapi and the original
 * CGI code, no doubt with many new and interesting bugs created... :)
 */

#include "php.h"
#include "SAPI.h"
#include "php_main.h"
#include "php_fastcgi.h"
#include "php_variables.h"

#include "fcgi_config.h"
#include "fcgiapp.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>


#define TLS_D
#define TLS_DC
#define TLS_C
#define TLS_CC
#define TLS_FETCH()


FCGX_Stream *in, *out, *err;
FCGX_ParamArray envp;
char *path_info = NULL;

/* Our original environment from when the FastCGI first started */
char **orig_env;

/* The environment given by the FastCGI */
char **cgi_env;

/* The manufactured environment, from merging the base environ with
 * the parameters set by the per-connection environment
 */
char **merge_env;


static int sapi_fastcgi_ub_write(const char *str, uint str_length)
{
        uint sent = FCGX_PutStr( str, str_length, out );
        return sent;
}


static void sapi_fastcgi_flush( void *server_context )
{
        if( FCGX_FFlush( out ) == -1 ) {
                php_handle_aborted_connection();
        }
}


static int sapi_fastcgi_send_headers(sapi_headers_struct *sapi_headers SLS_DC)
{
        char buf[1024];
        int n = 0;
        zend_llist_position pos;
        sapi_header_struct *h;

        switch( sapi_headers->http_response_code ) {
        case 200:
                /* Default, assumed by FastCGI */
                break;
        case 302:
                FCGX_PutS( "Status: 302 Moved Temporarily\r\n", out );
                break;
        case 401:
                FCGX_PutS( "Status: 401 Authorization Required\r\n", out );
                break;
        default:
                FCGX_FPrintF( out, "Status: %d Undescribed\r\\n",
                              sapi_headers->http_response_code );
        }
        
        h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
        while (h) {
                /* TODO: Buffer headers together into one big Put? */
#ifdef DEBUG_FASTCGI
                fprintf( stderr, "Printing header %s\n", h->header );
#endif
                FCGX_PutStr( h->header, h->header_len, out );
                FCGX_PutStr( "\r\n", 2, out );
                h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
        }
        FCGX_PutStr( "\r\n", 2, out );
        
        return SAPI_HEADER_SENT_SUCCESSFULLY;
}

static int sapi_fastcgi_read_post(char *buffer, uint count_bytes SLS_DC)
{
        size_t read_bytes = 0, tmp;
        int c;
        char *pos = buffer;
        TLS_FETCH();

        while( count_bytes ) {
                c = FCGX_GetStr( pos, count_bytes, in );
                read_bytes += c;
                count_bytes -= c;
                pos += c;
                if( !c ) break;
        }
        return read_bytes;
}

static char *sapi_fastcgi_read_cookies(SLS_D)
{
        return getenv( "HTTP_COOKIE" );
}


static void sapi_fastcgi_register_variables(zval *track_vars_array ELS_DC SLS_DC 
PLS_DC)
{
        char *self = getenv("REQUEST_URI");
        char *ptr = strchr( self, '?' );

        /* In CGI mode, we consider the environment to be a part of the server
         * variables
         */
        php_import_environment_variables(track_vars_array ELS_CC PLS_CC);

        /* strip query string off this */
        if ( ptr ) *ptr = 0;
        php_register_variable( "PHP_SELF", getenv("REQUEST_URI"), track_vars_array 
ELS_CC PLS_CC);
        if ( ptr ) *ptr = '?';
}


static sapi_module_struct fastcgi_sapi_module = {
        "fastcgi",
        "FastCGI",
        
        php_module_startup,
        php_module_shutdown_wrapper,
        
        NULL,                                                                   /* 
activate */
        NULL,                                                                   /* 
deactivate */

        sapi_fastcgi_ub_write,
        sapi_fastcgi_flush,
        NULL,                                                                   /* get 
uid */
        NULL,                                                                   /* 
getenv */

        php_error,
        
        NULL,
        sapi_fastcgi_send_headers,
        NULL,
        sapi_fastcgi_read_post,
        sapi_fastcgi_read_cookies,

        sapi_fastcgi_register_variables,
        NULL,                                                                   /* Log 
message */

        NULL,                                                                   /* 
Block interruptions */
        NULL,                                                                   /* 
Unblock interruptions */

        STANDARD_SAPI_MODULE_PROPERTIES
};

static void fastcgi_module_main(TLS_D SLS_DC)
{
        zend_file_handle file_handle;
        CLS_FETCH();
        ELS_FETCH();
        PLS_FETCH();

        file_handle.type = ZEND_HANDLE_FILENAME;
        file_handle.filename = SG(request_info).path_translated;
        file_handle.free_filename = 0;
        file_handle.opened_path = NULL;

        if (php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC) == SUCCESS) {
                php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC);
        }
        php_request_shutdown(NULL);
}


static void init_request_info( SLS_D )
{
        char *content_length = getenv("CONTENT_LENGTH");
        const char *auth;
        struct stat st;
        char *pi = getenv( "PATH_INFO" );
        char *pt = getenv( "PATH_TRANSLATED" );
        path_info = strdup( pi );

        SG(request_info).request_method = getenv("REQUEST_METHOD");
        SG(request_info).query_string = getenv("QUERY_STRING");
        SG(request_info).request_uri = path_info;
        SG(request_info).content_type = getenv("CONTENT_TYPE");
        SG(request_info).content_length = (content_length?atoi(content_length):0);
        SG(sapi_headers).http_response_code = 200;

        SG(request_info).path_translated = pt;
        /*
         * if the file doesn't exist, try to extract PATH_INFO out
         * of it by stat'ing back through the '/'
         */
        if ( stat( pt, &st ) == -1 ) {
           int len = strlen(pt);
           char *ptr;
           while( ptr = strrchr(pt,'/') ) {
              *ptr = 0;
              if ( stat(pt,&st) == 0 && S_ISREG(st.st_mode) ) {
                 /*
                  * okay, we found the base script!
                  * work out how many chars we had to strip off;
                  * then we can modify PATH_INFO
                  * accordingly
                  */
                 int slen = len - strlen(pt);
                 if ( pi ) {
                    int pilen = strlen( pi );
                    strcpy( pi, pi + pilen - slen );
                 }
                 break;
              }
           }
           /*
            * if we stripped out all the '/' and still didn't find
            * a valid path... we will fail, badly. of course we would
            * have failed anyway... is there a nice way to error?
            */
        } else {
           /* the first stat succeeded... */
           if ( pi ) *pi = 0;
        }

        /* The CGI RFC allows servers to pass on unvalidated Authorization data */
        auth = getenv("HTTP_AUTHORIZATION");
#ifdef DEBUG_FASTCGI
        fprintf( stderr, "Authorization: %s\n", auth );
#endif
        php_handle_auth_data(auth SLS_CC);


}


void fastcgi_php_init(void)
{
        sapi_startup(&fastcgi_sapi_module);
        fastcgi_sapi_module.startup(&fastcgi_sapi_module);
        SG(server_context) = (void *) 1;
}

void fastcgi_php_shutdown(void)
{
        if (SG(server_context) != NULL) {
                fastcgi_sapi_module.shutdown(&fastcgi_sapi_module);
                sapi_shutdown();
        }
}


int main(int argc, char *argv[])
{
        int exit_status = SUCCESS;
        int c, i, len;
        zend_file_handle file_handle;
        char *s;
        char *argv0=NULL;
        char *script_file=NULL;
        zend_llist global_vars;
        int children = 8;
        int max_requests = 500;
        int requests = 0;
        int status;
        int env_size;

#ifdef FASTCGI_DEBUG
        fprintf( stderr, "Initialising now!\n" );
#endif

        /* Calculate environment size */
        env_size = 0;
        while( environ[ env_size ] ) { env_size++; }
        /* Also include the final NULL pointer */
        env_size++;

        /* Allocate for our environment */
        orig_env = malloc( env_size * sizeof( char *));
        if( !orig_env ) {
                perror( "Can't malloc environment" );
                exit( 1 );
        }
        memcpy( orig_env, environ, env_size * sizeof( char *));

#ifdef HAVE_SIGNAL_H
#if defined(SIGPIPE) && defined(SIG_IGN)
        signal(SIGPIPE,SIG_IGN); /* ignore SIGPIPE in standalone mode so
                                    that sockets created via fsockopen()
                                    don't kill PHP if the remote site
                                    closes it.  in apache|apxs mode apache
                                    does that for us!  [EMAIL PROTECTED]
                                    20000419 */
#endif
#endif

        sapi_startup(&fastcgi_sapi_module);

        if (php_module_startup(&fastcgi_sapi_module)==FAILURE) {
                return FAILURE;
        }

        /* How many times to run PHP scripts before dying */
        if( getenv( "PHP_FCGI_MAX_REQUESTS" )) {
                max_requests = atoi( getenv( "PHP_FCGI_MAX_REQUESTS" ));
                if( !max_requests ) {
                        fprintf( stderr,
                                 "PHP_FCGI_MAX_REQUESTS is not valid\n" );
                        exit( 1 );
                }
        }

        /* Pre-fork, if required */
        if( getenv( "PHP_FCGI_CHILDREN" )) {
                children = atoi( getenv( "PHP_FCGI_CHILDREN" ));
                if( !children ) {
                        fprintf( stderr,
                                 "PHP_FCGI_CHILDREN is not valid\n" );
                        exit( 1 );
                }
        }

        if( children ) {
                int parent = 1;
                int running = 0;
                while( parent ) {
                        do {
#ifdef FASTCGI_DEBUG
                                fprintf( stderr, "Forking, %d running\n",
                                         running );
#endif
                                switch( fork() ) {
                                case 0:
                                        /* One of the children.
                                         * Make sure we don't go round the
                                         * fork loop any more
                                         */
                                        parent = 0;
                                        break;
                                case -1:
                                        perror( "php (pre-forking)" );
                                        exit( 1 );
                                        break;
                                default:
                                        /* Fine */
                                        running++;
                                        break;
                                }
                        } while( parent && ( running < children ));

                        if( parent ) {
                                wait( &status );
                                running--;
                        }
                }
        }

        /* Main FastCGI loop */
#ifdef FASTCGI_DEBUG
        fprintf( stderr, "Going into accept loop\n" );
#endif

        while( FCGX_Accept( &in, &out, &err, &cgi_env ) >= 0 ) {

#ifdef FASTCGI_DEBUG
                fprintf( stderr, "Got accept\n" );
#endif

                /* Allocate for our environment */
                merge_env = malloc( env_size * sizeof( char *));
                if( !merge_env ) {
                        perror( "Can't malloc environment" );
                        exit( 1 );
                }
                memcpy( merge_env, orig_env, env_size * sizeof( char *));

                /* Use the new environment */
                environ = merge_env;

                /* Populate our environment with the CGI's */
                for( i = 0; cgi_env[ i ]; i++ ) {
                        putenv( cgi_env[ i ] );
                }

                init_request_info( TLS_C SLS_CC );
                SG(server_context) = (void *) 1; /* avoid server_context==NULL checks 
*/
                CG(extended_info) = 0;                
                SG(request_info).argv0 = argv0;                
                zend_llist_init(&global_vars, sizeof(char *), NULL, 0);

                fastcgi_module_main( TLS_C SLS_CC );
                if( path_info ) {
                   free( path_info );
                   path_info = NULL;
                }

                /* TODO: We should free our environment here, but
                 * some platforms are unhappy if they've altered our
                 * existing environment and we then free() the new
                 * environ pointer
                 */

                requests++;
                if( max_requests && ( requests == max_requests )) {
                        FCGX_Finish();
                        break;
                }
        }

#ifdef FASTCGI_DEBUG
        fprintf( stderr, "Exiting...\n" );
#endif
        return 0;
}

Index: php4/sapi/fastcgi/php.sym
+++ php4/sapi/fastcgi/php.sym

Index: php4/sapi/fastcgi/php_fastcgi.h
+++ php4/sapi/fastcgi/php_fastcgi.h
/*
   +----------------------------------------------------------------------+
   | PHP version 4.0                                                      |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2001 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 2.02 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available at through the world-wide-web at                           |
   | http://www.php.net/license/2_02.txt.                                 |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Sascha Schumann <[EMAIL PROTECTED]>                         |
   +----------------------------------------------------------------------+
*/

#ifndef PHP_FASTCGI_H
#define PHP_FASTCGI_H

#include <sys/types.h>
#include <sys/stat.h>

void     fastcgi_php_shutdown(void);
void     fastcgi_php_init(void);

#endif

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]

Reply via email to