summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--configure.in5
-rw-r--r--sapi/fastcgi/CREDITS4
-rw-r--r--sapi/fastcgi/Makefile.in5
-rw-r--r--sapi/fastcgi/README.FastCGI17
-rw-r--r--sapi/fastcgi/config.m422
-rw-r--r--sapi/fastcgi/fastcgi.c457
-rw-r--r--sapi/fastcgi/php.sym0
-rw-r--r--sapi/fastcgi/php_fastcgi.h28
9 files changed, 539 insertions, 1 deletions
diff --git a/Makefile.in b/Makefile.in
index 81d2b7a600..6968ba80fc 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -18,7 +18,7 @@ LTLIBRARY_LIBADD = $(LTLIBRARY_DEPENDENCIES) $(EXTRA_LIBS)
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)
diff --git a/configure.in b/configure.in
index a22c290946..d596970246 100644
--- a/configure.in
+++ b/configure.in
@@ -645,6 +645,11 @@ if test "$PHP_SAPI" = "cgi"; then
PHP_PROGRAM=php
fi
+if test "$PHP_SAPI" = "fastcgi"; then
+ PHP_PROGRAM=php
+fi
+
+
PHP_REGEX
PHP_CONFIGURE_PART(Configuring Zend)
diff --git a/sapi/fastcgi/CREDITS b/sapi/fastcgi/CREDITS
new file mode 100644
index 0000000000..eb9cece428
--- /dev/null
+++ b/sapi/fastcgi/CREDITS
@@ -0,0 +1,4 @@
+fastcgi
+Ben Mansell
+Stephen Landamore
+Daniel Silverstone
diff --git a/sapi/fastcgi/Makefile.in b/sapi/fastcgi/Makefile.in
new file mode 100644
index 0000000000..0bea9c31b1
--- /dev/null
+++ b/sapi/fastcgi/Makefile.in
@@ -0,0 +1,5 @@
+
+LTLIBRARY_NAME = libsapi.la
+LTLIBRARY_SOURCES = fastcgi.c
+
+include $(top_srcdir)/build/ltlib.mk
diff --git a/sapi/fastcgi/README.FastCGI b/sapi/fastcgi/README.FastCGI
new file mode 100644
index 0000000000..65dbc44ea0
--- /dev/null
+++ b/sapi/fastcgi/README.FastCGI
@@ -0,0 +1,17 @@
+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.
diff --git a/sapi/fastcgi/config.m4 b/sapi/fastcgi/config.m4
new file mode 100644
index 0000000000..7e9c39e0b5
--- /dev/null
+++ b/sapi/fastcgi/config.m4
@@ -0,0 +1,22 @@
+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)
diff --git a/sapi/fastcgi/fastcgi.c b/sapi/fastcgi/fastcgi.c
new file mode 100644
index 0000000000..8db43ae792
--- /dev/null
+++ b/sapi/fastcgi/fastcgi.c
@@ -0,0 +1,457 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Ben Mansell <php@slimyhorror.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* 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! thies@thieso.net
+ 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;
+}
diff --git a/sapi/fastcgi/php.sym b/sapi/fastcgi/php.sym
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/sapi/fastcgi/php.sym
diff --git a/sapi/fastcgi/php_fastcgi.h b/sapi/fastcgi/php_fastcgi.h
new file mode 100644
index 0000000000..9031d7bd11
--- /dev/null
+++ b/sapi/fastcgi/php_fastcgi.h
@@ -0,0 +1,28 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Sascha Schumann <sascha@schumann.cx> |
+ +----------------------------------------------------------------------+
+*/
+
+#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