andi            Tue Mar 20 10:13:21 2001 EDT

  Added files:                 (Branch: PHP_4_0_5)
    /php4/sapi/fastcgi  CREDITS Makefile.in README.FastCGI config.m4 
                        fastcgi.c php.sym php_fastcgi.h 
  Log:
  - MFH
  
  

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