Back to index

php5  5.3.10
mod_php5.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                                                             |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                                          |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,    |
00008    | that is bundled with this package in the file LICENSE, and is             |
00009    | available at through the world-wide-web at                                           |
00010    | http://www.php.net/license/3_01.txt                                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to               |
00013    | license@php.net so we can mail you a copy immediately.                        |
00014    +----------------------------------------------------------------------+
00015    | Authors: Rasmus Lerdorf <rasmus@php.net>                                                |
00016    | (with helpful hints from Dean Gaudet <dgaudet@arctic.org>                 |
00017    | PHP 4.0 patches by Zeev Suraski <zeev@zend.com>                                  |
00018    +----------------------------------------------------------------------+
00019  */
00020 /* $Id: mod_php5.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include "php_apache_http.h"
00023 
00024 #ifdef NETWARE
00025 #define SIGPIPE SIGINT
00026 #endif
00027 
00028 #undef shutdown
00029 
00030 /* {{{ Prototypes
00031  */
00032 int apache_php_module_main(request_rec *r, int display_source_mode TSRMLS_DC);
00033 static void php_save_umask(void);
00034 static void php_restore_umask(void);
00035 static int sapi_apache_read_post(char *buffer, uint count_bytes TSRMLS_DC);
00036 static char *sapi_apache_read_cookies(TSRMLS_D);
00037 static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
00038 static int sapi_apache_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC);
00039 static int send_php(request_rec *r, int display_source_mode, char *filename);
00040 static int send_parsed_php(request_rec * r);
00041 static int send_parsed_php_source(request_rec * r);
00042 static int php_xbithack_handler(request_rec * r);
00043 static void php_init_handler(server_rec *s, pool *p);
00044 /* }}} */
00045 
00046 #if MODULE_MAGIC_NUMBER >= 19970728
00047 static void php_child_exit_handler(server_rec *s, pool *p);
00048 #endif
00049 
00050 #if MODULE_MAGIC_NUMBER > 19961007
00051 #define CONST_PREFIX const
00052 #else
00053 #define CONST_PREFIX
00054 #endif
00055 
00056 
00057 typedef struct _sapi_stack {
00058               int top, max, persistent;
00059               void **elements;
00060 } sapi_stack;
00061 
00062 typedef struct _php_per_dir_config {
00063        HashTable *ini_settings;
00064        sapi_stack headers_handlers;
00065        sapi_stack auth_handlers;
00066        sapi_stack access_handlers;
00067        sapi_stack type_handlers;
00068        sapi_stack fixup_handlers;
00069        sapi_stack logger_handlers;
00070        sapi_stack post_read_handlers;
00071        sapi_stack response_handlers;
00072 } php_per_dir_config;
00073 
00074 typedef struct _php_per_server_config {
00075        sapi_stack uri_handlers;
00076        sapi_stack requires;
00077 } php_per_server_config;
00078 
00079 
00080 static CONST_PREFIX char *php_apache_value_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode);
00081 static CONST_PREFIX char *php_apache_value_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1, char *arg2);
00082 static CONST_PREFIX char *php_apache_admin_value_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1, char *arg2);
00083 static CONST_PREFIX char *php_apache_flag_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1, char *arg2);
00084 static CONST_PREFIX char *php_apache_flag_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode);
00085 static CONST_PREFIX char *php_apache_admin_flag_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1, char *arg2);
00086 
00087 /* ### these should be defined in mod_php5.h or somewhere else */
00088 #define USE_PATH 1
00089 #define IGNORE_URL 2
00090 
00091 module MODULE_VAR_EXPORT php5_module;
00092 
00093 int saved_umask;
00094 /* static int setup_env = 0; */
00095 static unsigned char apache_php_initialized;
00096 
00097 typedef struct _php_per_dir_entry {
00098        char *key;
00099        char *value;
00100        uint key_length;
00101        uint value_length;
00102        int type;
00103 } php_per_dir_entry;
00104 
00105 /* some systems are missing these from their header files */
00106 
00107 /* {{{ zend stack utility functions
00108  */
00109 
00110 /* This code is ripped part and parcel from zend_stack.[ch].  Assuming that the
00111    patch supporting zend_stack_init_ex is applied, all but the bottom two 
00112    module-specific iterators will be removed
00113  */
00114 
00115 int sapi_stack_init_ex(sapi_stack *stack, int persistent)
00116 {
00117               stack->top = 0;
00118               stack->persistent = persistent;
00119               stack->elements = (void **) pemalloc(sizeof(void **) * STACK_BLOCK_SIZE,  persistent);
00120               if (!stack->elements) {
00121                             return FAILURE;
00122               } else {
00123                             stack->max = STACK_BLOCK_SIZE;
00124                             return SUCCESS;
00125               }
00126 }
00127 int sapi_stack_push(sapi_stack *stack, void *element)
00128 {
00129               if (stack->top >= stack->max) {            /* we need to allocate more memory */
00130                             stack->elements = (void **) perealloc(stack->elements,
00131                                                            (sizeof(void **) * (stack->max += STACK_BLOCK_SIZE)), stack->persistent);
00132                             if (!stack->elements) {
00133                                           return FAILURE;
00134                             }
00135               }
00136               stack->elements[stack->top] = (void *) element;
00137               return stack->top++;
00138 }
00139 void* sapi_stack_pop(sapi_stack *stack) {
00140        if(stack->top == 0) {
00141               return NULL;
00142        }
00143        else {
00144               return stack->elements[--stack->top];
00145        }
00146 }
00147 
00148 int sapi_stack_destroy(sapi_stack *stack)
00149 {
00150               return SUCCESS;
00151 }
00152 
00153 int sapi_stack_apply_with_argument_all(sapi_stack *stack, int type, int (*apply_function)(void *element, void *arg), void *arg)
00154 {
00155               int i, retval;   
00156 
00157               switch (type) {                           
00158                             case ZEND_STACK_APPLY_TOPDOWN:
00159                                           for (i=stack->top-1; i>=0; i--) {
00160                                                         retval = apply_function(stack->elements[i], arg); 
00161                                           }
00162                                           break;
00163                             case ZEND_STACK_APPLY_BOTTOMUP:
00164                                           for (i=0; i<stack->top; i++) {            
00165                                                         retval = apply_function(stack->elements[i], arg);
00166                                           }        
00167                                           break;
00168               }
00169               return retval;
00170 }
00171 
00172 
00173 int sapi_stack_apply_with_argument_stop_if_equals(sapi_stack *stack, int type, int (*apply_function)(void *element, void *arg), void *arg, int stopval)
00174 {
00175        int i;
00176        int ret = DECLINED;
00177        switch (type) {
00178               case ZEND_STACK_APPLY_TOPDOWN:
00179                      for (i=stack->top-1; i>=0; i--) {
00180                             if ((ret = apply_function(stack->elements[i], arg)) == stopval) {
00181                                    break;
00182                             }
00183                      }
00184                      break;
00185               case ZEND_STACK_APPLY_BOTTOMUP:
00186                      for (i=0; i<stack->top; i++) {
00187                             if ((ret = apply_function(stack->elements[i], arg)) == stopval) {
00188                                    break;
00189                             }
00190                      }
00191                      break;
00192        }
00193        return ret;
00194 }
00195 
00196 int sapi_stack_apply_with_argument_stop_if_http_error(sapi_stack *stack, int type, int (*apply_function)(void *element, void *arg), void *arg)
00197 {
00198        int i;
00199        int ret = DECLINED;
00200        switch (type) {
00201               case ZEND_STACK_APPLY_TOPDOWN:
00202                      for (i=stack->top-1; i>=0; i--) {
00203                             if ((ret = apply_function(stack->elements[i], arg)) > 0) {
00204                                    break;
00205                             }
00206                      }
00207                      break;
00208               case ZEND_STACK_APPLY_BOTTOMUP:
00209                      for (i=0; i<stack->top; i++) {
00210                             if ((ret = apply_function(stack->elements[i], arg)) > 0) {
00211                                    break;
00212                             }
00213                      }
00214                      break;
00215        }
00216        return ret;
00217 }
00218 
00219 void php_handler_stack_destroy(sapi_stack *stack)
00220 {
00221        php_handler *ph;
00222        while((ph = (php_handler *)sapi_stack_pop(stack)) != NULL) {
00223               free(ph->name);
00224               free(ph);
00225        }
00226 }
00227 /* }}} */ 
00228 
00229 /* {{{ php_save_umask
00230  */
00231 static void php_save_umask(void)
00232 {
00233        saved_umask = umask(077);
00234        umask(saved_umask);
00235 }
00236 /* }}} */
00237 
00238 /* {{{ sapi_apache_ub_write
00239  */
00240 static int sapi_apache_ub_write(const char *str, uint str_length TSRMLS_DC)
00241 {
00242        int ret=0;
00243               
00244        if (SG(server_context)) {
00245               ret = rwrite(str, str_length, (request_rec *) SG(server_context));
00246        }
00247        if (ret != str_length) {
00248               php_handle_aborted_connection();
00249        }
00250        return ret;
00251 }
00252 /* }}} */
00253 
00254 /* {{{ sapi_apache_flush
00255  */
00256 static void sapi_apache_flush(void *server_context)
00257 {
00258        if (server_context) {
00259 #if MODULE_MAGIC_NUMBER > 19970110
00260               rflush((request_rec *) server_context);
00261 #else
00262               bflush((request_rec *) server_context->connection->client);
00263 #endif
00264        }
00265 }
00266 /* }}} */
00267 
00268 /* {{{ sapi_apache_read_post
00269  */
00270 static int sapi_apache_read_post(char *buffer, uint count_bytes TSRMLS_DC)
00271 {
00272        uint total_read_bytes=0, read_bytes;
00273        request_rec *r = (request_rec *) SG(server_context);
00274        void (*handler)(int);
00275 
00276        /*
00277         * This handles the situation where the browser sends a Expect: 100-continue header
00278         * and needs to recieve confirmation from the server on whether or not it can send
00279         * the rest of the request. RFC 2616
00280         *
00281         */
00282        if (!SG(read_post_bytes) && !ap_should_client_block(r)) {
00283               return total_read_bytes;
00284        }
00285  
00286        handler = signal(SIGPIPE, SIG_IGN);
00287        while (total_read_bytes<count_bytes) {
00288               hard_timeout("Read POST information", r); /* start timeout timer */
00289               read_bytes = get_client_block(r, buffer+total_read_bytes, count_bytes-total_read_bytes);
00290               reset_timeout(r);
00291               if (read_bytes<=0) {
00292                      break;
00293               }
00294               total_read_bytes += read_bytes;
00295        }
00296        signal(SIGPIPE, handler);   
00297        return total_read_bytes;
00298 }
00299 /* }}} */
00300 
00301 /* {{{ sapi_apache_read_cookies
00302  */
00303 static char *sapi_apache_read_cookies(TSRMLS_D)
00304 {
00305        return (char *) table_get(((request_rec *) SG(server_context))->subprocess_env, "HTTP_COOKIE");
00306 }
00307 /* }}} */
00308 
00309 /* {{{ sapi_apache_header_handler
00310  */
00311 static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
00312 {
00313        char *header_name, *header_content, *p;
00314        request_rec *r = (request_rec *) SG(server_context);
00315        if(!r) {
00316               return 0;
00317        }
00318 
00319        switch(op) {
00320               case SAPI_HEADER_DELETE_ALL:
00321                      clear_table(r->headers_out);
00322                      return 0;
00323 
00324               case SAPI_HEADER_DELETE:
00325                      table_unset(r->headers_out, sapi_header->header);
00326                      return 0;
00327 
00328               case SAPI_HEADER_ADD:
00329               case SAPI_HEADER_REPLACE:
00330                      header_name = sapi_header->header;
00331 
00332                      header_content = p = strchr(header_name, ':');
00333                      if (!p) {
00334                             return 0;
00335                      }
00336 
00337                      *p = 0;
00338                      do {
00339                             header_content++;
00340                      } while (*header_content==' ');
00341 
00342                      if (!strcasecmp(header_name, "Content-Type")) {
00343                             r->content_type = pstrdup(r->pool, header_content);
00344                      } else if (!strcasecmp(header_name, "Set-Cookie")) {
00345                             table_add(r->headers_out, header_name, header_content);
00346                      } else if (op == SAPI_HEADER_REPLACE) {
00347                             table_set(r->headers_out, header_name, header_content);
00348                      } else {
00349                             table_add(r->headers_out, header_name, header_content);
00350                      }
00351 
00352                      *p = ':';  /* a well behaved header handler shouldn't change its original arguments */
00353 
00354                      return SAPI_HEADER_ADD;
00355 
00356               default:
00357                      return 0;
00358        }
00359 }
00360 /* }}} */
00361 
00362 /* {{{ sapi_apache_send_headers
00363  */
00364 static int sapi_apache_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00365 {
00366        if(SG(server_context) == NULL) { /* server_context is not here anymore */
00367               return SAPI_HEADER_SEND_FAILED;
00368        }
00369 
00370        ((request_rec *) SG(server_context))->status = SG(sapi_headers).http_response_code;
00371        /* check that we haven't sent headers already, we use our own
00372         * headers_sent since we may send headers at anytime 
00373         */
00374        if(!AP(headers_sent)) {
00375               send_http_header((request_rec *) SG(server_context));
00376               AP(headers_sent) = 1;
00377        }
00378        return SAPI_HEADER_SENT_SUCCESSFULLY;
00379 }
00380 /* }}} */
00381 
00382 /* {{{ sapi_apache_register_server_variables
00383  */
00384 static void sapi_apache_register_server_variables(zval *track_vars_array TSRMLS_DC)
00385 {
00386        register int i;
00387        array_header *arr = table_elts(((request_rec *) SG(server_context))->subprocess_env);
00388        table_entry *elts = (table_entry *) arr->elts;
00389        zval **path_translated;
00390        HashTable *symbol_table;
00391 
00392        for (i = 0; i < arr->nelts; i++) {
00393               char *val;
00394 
00395               if (elts[i].val) {
00396                      val = elts[i].val;
00397               } else {
00398                      val = "";
00399               }
00400               php_register_variable(elts[i].key, val, track_vars_array  TSRMLS_CC);
00401        }
00402 
00403        /* If PATH_TRANSLATED doesn't exist, copy it from SCRIPT_FILENAME */
00404        if (track_vars_array) {
00405               symbol_table = track_vars_array->value.ht;
00406        } else if (PG(register_globals)) {
00407               /* should never happen nowadays */
00408               symbol_table = EG(active_symbol_table);
00409        } else {
00410               symbol_table = NULL;
00411        }
00412        if (symbol_table
00413               && !zend_hash_exists(symbol_table, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"))
00414               && zend_hash_find(symbol_table, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &path_translated)==SUCCESS) {
00415               php_register_variable("PATH_TRANSLATED", Z_STRVAL_PP(path_translated), track_vars_array TSRMLS_CC);
00416        }
00417 
00418        php_register_variable("PHP_SELF", ((request_rec *) SG(server_context))->uri, track_vars_array TSRMLS_CC);
00419 }
00420 /* }}} */
00421 
00422 /* {{{ php_apache_startup
00423  */
00424 static int php_apache_startup(sapi_module_struct *sapi_module)
00425 {
00426        if (php_module_startup(sapi_module, &apache_module_entry, 1) == FAILURE) {
00427               return FAILURE;
00428        } else {
00429               return SUCCESS;
00430        }
00431 }
00432 /* }}} */
00433 
00434 /* {{{ php_apache_log_message
00435  */
00436 static void php_apache_log_message(char *message)
00437 {
00438        TSRMLS_FETCH();
00439 
00440        if (SG(server_context)) {
00441 #if MODULE_MAGIC_NUMBER >= 19970831
00442               aplog_error(NULL, 0, APLOG_ERR | APLOG_NOERRNO, ((request_rec *) SG(server_context))->server, "%s", message);
00443 #else
00444               log_error(message, ((request_rec *) SG(server_context))->server);
00445 #endif
00446        } else {
00447               fprintf(stderr, "%s", message);
00448               fprintf(stderr, "\n");
00449        }
00450 }
00451 /* }}} */
00452 
00453 /* {{{ php_apache_request_shutdown
00454  */
00455 static void php_apache_request_shutdown(void *dummy)
00456 {
00457        TSRMLS_FETCH();
00458        AP(current_hook) = AP_CLEANUP;
00459        php_output_set_status(0 TSRMLS_CC);
00460        SG(server_context) = NULL; /* The server context (request) is invalid by the time run_cleanups() is called */
00461        if(SG(sapi_started)) {
00462               php_request_shutdown(dummy);
00463               SG(sapi_started) = 0;
00464        }
00465        AP(in_request) = 0;
00466        if(AP(setup_env)) {
00467               AP(setup_env) = 0;
00468        }
00469        AP(current_hook) = AP_WAITING_FOR_REQUEST;
00470        AP(headers_sent) = 0;
00471 }
00472 /* }}} */
00473 
00474 /* {{{ php_apache_sapi_activate
00475  */
00476 static int php_apache_sapi_activate(TSRMLS_D)
00477 {
00478        request_rec *r = (request_rec *) SG(server_context); 
00479 
00480        /*
00481         * For the Apache module version, this bit of code registers a cleanup
00482         * function that gets triggered when our request pool is destroyed.
00483         * We need this because at any point in our code we can be interrupted
00484         * and that may happen before we have had time to free our memory.
00485         * The php_request_shutdown function needs to free all outstanding allocated
00486         * memory.  
00487         */
00488        block_alarms();
00489        register_cleanup(r->pool, NULL, php_apache_request_shutdown, php_request_shutdown_for_exec);
00490        AP(in_request)=1;
00491        unblock_alarms();
00492 
00493        /* Override the default headers_only value - sometimes "GET" requests should actually only
00494         * send headers.
00495         */
00496        SG(request_info).headers_only = r->header_only;
00497        return SUCCESS;
00498 }
00499 /* }}} */
00500 
00501 /* {{{ php_apache_get_stat
00502  */
00503 static struct stat *php_apache_get_stat(TSRMLS_D)
00504 {
00505        return &((request_rec *) SG(server_context))->finfo;
00506 }
00507 /* }}} */
00508 
00509 /* {{{ php_apache_getenv
00510  */
00511 static char *php_apache_getenv(char *name, size_t name_len TSRMLS_DC)
00512 {
00513        return (char *) table_get(((request_rec *) SG(server_context))->subprocess_env, name);
00514 }
00515 /* }}} */
00516 
00517 /* {{{ sapi_module_struct apache_sapi_module
00518  */
00519 static sapi_module_struct apache_sapi_module = {
00520        "apache",                                        /* name */
00521        "Apache",                                        /* pretty name */
00522                                                                
00523        php_apache_startup,                       /* startup */
00524        php_module_shutdown_wrapper,       /* shutdown */
00525 
00526        php_apache_sapi_activate,          /* activate */
00527        NULL,                                            /* deactivate */
00528 
00529        sapi_apache_ub_write,                     /* unbuffered write */
00530        sapi_apache_flush,                        /* flush */
00531        php_apache_get_stat,               /* get uid */
00532        php_apache_getenv,                        /* getenv */
00533 
00534        php_error,                                       /* error handler */
00535 
00536        sapi_apache_header_handler,        /* header handler */
00537        sapi_apache_send_headers,          /* send headers handler */
00538        NULL,                                            /* send header handler */
00539 
00540        sapi_apache_read_post,                    /* read POST data */
00541        sapi_apache_read_cookies,          /* read Cookies */
00542 
00543        sapi_apache_register_server_variables,           /* register server variables */
00544        php_apache_log_message,                   /* Log message */
00545        NULL,                                            /* Get request time */
00546        NULL,                              /* child terminate */
00547 
00548        NULL,                                            /* php.ini path override */
00549 
00550 #ifdef PHP_WIN32
00551        NULL,
00552        NULL,
00553 #else
00554        block_alarms,                             /* Block interruptions */
00555        unblock_alarms,                                  /* Unblock interruptions */
00556 #endif
00557 
00558        NULL,                           /* default post reader */
00559        NULL,                           /* treat data */
00560        NULL,                           /* exe location */
00561        0,                              /* ini ignore */
00562        NULL
00563        
00564 };
00565 /* }}} */
00566 
00567 /* {{{ php_restore_umask
00568  */
00569 static void php_restore_umask(void)
00570 {
00571        umask(saved_umask);
00572 }
00573 /* }}} */
00574 
00575 /* {{{ init_request_info
00576  */
00577 static void init_request_info(TSRMLS_D)
00578 {
00579        request_rec *r = ((request_rec *) SG(server_context));
00580        char *content_length = (char *) table_get(r->subprocess_env, "CONTENT_LENGTH");
00581        const char *authorization=NULL;
00582        char *tmp, *tmp_user;
00583 
00584        SG(request_info).query_string = r->args;
00585        SG(request_info).path_translated = r->filename;
00586        SG(request_info).request_uri = r->uri;
00587        SG(request_info).request_method = (char *)r->method;
00588        SG(request_info).proto_num = r->proto_num;
00589        SG(request_info).content_type = (char *) table_get(r->subprocess_env, "CONTENT_TYPE");
00590        SG(request_info).content_length = (content_length ? atol(content_length) : 0);
00591        SG(sapi_headers).http_response_code = r->status;
00592 
00593        if (r->headers_in) {
00594               authorization = table_get(r->headers_in, "Authorization");
00595        }
00596 
00597        SG(request_info).auth_user = NULL;
00598        SG(request_info).auth_password = NULL;
00599 
00600        if (authorization && !auth_type(r)) {
00601         if (!strcasecmp(getword(r->pool, &authorization, ' '), "Basic")) {
00602             tmp = uudecode(r->pool, authorization);
00603             tmp_user = getword_nulls_nc(r->pool, &tmp, ':');
00604             if (tmp_user) {
00605                 r->connection->user = pstrdup(r->connection->pool, tmp_user);
00606                 r->connection->ap_auth_type = "Basic";
00607                 SG(request_info).auth_user = estrdup(tmp_user);
00608             }
00609             if (tmp) {
00610                 SG(request_info).auth_password = estrdup(tmp);
00611             }
00612               } else if  (!strcasecmp(getword(r->pool, &authorization, ' '), "Digest")) {
00613             r->connection->ap_auth_type = "Digest";
00614             SG(request_info).auth_digest = estrdup(authorization);
00615               }
00616        }
00617 }
00618 /* }}} */
00619 
00620 /* {{{ php_apache_alter_ini_entries
00621  */
00622 static int php_apache_alter_ini_entries(php_per_dir_entry *per_dir_entry TSRMLS_DC)
00623 {
00624        zend_alter_ini_entry(per_dir_entry->key, per_dir_entry->key_length+1, per_dir_entry->value, per_dir_entry->value_length, per_dir_entry->type, PHP_INI_STAGE_ACTIVATE);
00625        return 0;
00626 }
00627 /* }}} */
00628 
00629 /* {{{ php_apache_get_default_mimetype
00630  */
00631 static char *php_apache_get_default_mimetype(request_rec *r TSRMLS_DC)
00632 {
00633        
00634        char *mimetype;
00635        if (SG(default_mimetype) || SG(default_charset)) {
00636               /* Assume output will be of the default MIME type.  Individual
00637                  scripts may change this later. */
00638               char *tmpmimetype;
00639               tmpmimetype = sapi_get_default_content_type(TSRMLS_C);
00640               mimetype = pstrdup(r->pool, tmpmimetype);
00641               efree(tmpmimetype);
00642        } else {
00643               mimetype = SAPI_DEFAULT_MIMETYPE "; charset=" SAPI_DEFAULT_CHARSET;
00644        }
00645        return mimetype;
00646 }
00647 /* }}} */
00648 
00649 /* {{{ send_php
00650  */
00651 static int send_php(request_rec *r, int display_source_mode, char *filename)
00652 {
00653        int retval;
00654        php_per_dir_config *per_dir_conf;
00655        TSRMLS_FETCH();
00656        if (AP(in_request)) {
00657               zend_file_handle fh;
00658 
00659               fh.filename = r->filename;
00660               fh.opened_path = NULL;
00661               fh.free_filename = 0;
00662               fh.type = ZEND_HANDLE_FILENAME;
00663 
00664               zend_execute_scripts(ZEND_INCLUDE TSRMLS_CC, NULL, 1, &fh);
00665               return OK;
00666        }
00667 
00668        zend_first_try {
00669 
00670               /* Make sure file exists */
00671               if (filename == NULL && r->finfo.st_mode == 0) {
00672                      return DECLINED;
00673               }
00674 
00675               per_dir_conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
00676               if (per_dir_conf) {
00677                      zend_hash_apply((HashTable *) per_dir_conf->ini_settings, (apply_func_t) php_apache_alter_ini_entries TSRMLS_CC);
00678               }
00679 
00680               /* If PHP parser engine has been turned off with an "engine off"
00681                * directive, then decline to handle this request
00682                */
00683               if (!AP(engine)) {
00684                      r->content_type = php_apache_get_default_mimetype(r TSRMLS_CC);
00685                      r->allowed |= (1 << METHODS) - 1;
00686                      zend_try {
00687                             zend_ini_deactivate(TSRMLS_C);
00688                      } zend_end_try();
00689                      return DECLINED;
00690               }
00691               if (filename == NULL) {
00692                      filename = r->filename;
00693               }
00694 
00695               /* Apache 1.2 has a more complex mechanism for reading POST data */
00696 #if MODULE_MAGIC_NUMBER > 19961007
00697               if ((retval = setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
00698                      zend_try {
00699                             zend_ini_deactivate(TSRMLS_C);
00700                      } zend_end_try();
00701                      return retval;
00702               }
00703 #endif
00704 
00705               if (AP(last_modified)) {
00706 #if MODULE_MAGIC_NUMBER < 19970912
00707                      if ((retval = set_last_modified(r, r->finfo.st_mtime))) {
00708                             zend_try {
00709                                    zend_ini_deactivate(TSRMLS_C);
00710                             } zend_end_try();
00711                             return retval;
00712                      }
00713 #else
00714                      update_mtime (r, r->finfo.st_mtime);
00715                      set_last_modified(r);
00716                      set_etag(r);
00717 #endif
00718               }
00719               /* Assume output will be of the default MIME type.  Individual
00720                  scripts may change this later in the request. */
00721               r->content_type = php_apache_get_default_mimetype(r TSRMLS_CC);
00722 
00723               /* Init timeout */
00724               hard_timeout("send", r);
00725 
00726               SG(server_context) = r;
00727               
00728               php_save_umask();
00729               if(!AP(setup_env)) {
00730                      AP(setup_env) = 1;
00731                      add_common_vars(r);
00732                      add_cgi_vars(r);
00733               }
00734               init_request_info(TSRMLS_C);
00735               apache_php_module_main(r, display_source_mode TSRMLS_CC);
00736               
00737               /* Done, restore umask, turn off timeout, close file and return */
00738               php_restore_umask();
00739               kill_timeout(r);
00740        } zend_end_try();
00741 
00742        return OK;
00743 }
00744 /* }}} */
00745 
00746 /* {{{ send_parsed_php
00747  */
00748 static int send_parsed_php(request_rec * r)
00749 {
00750        int result = send_php(r, 0, NULL);
00751        TSRMLS_FETCH();
00752  
00753        ap_table_setn(r->notes, "mod_php_memory_usage",
00754               ap_psprintf(r->pool, "%u", zend_memory_peak_usage(1 TSRMLS_CC)));
00755 
00756        return result;
00757 }
00758 /* }}} */
00759 
00760 /* {{{ send_parsed_php_source
00761  */
00762 static int send_parsed_php_source(request_rec * r)
00763 {
00764        return send_php(r, 1, NULL);
00765 }
00766 /* }}} */
00767 
00768 
00769 /* {{{ destroy_per_dir_entry
00770  */
00771 static void destroy_per_dir_entry(php_per_dir_entry *per_dir_entry)
00772 {
00773        free(per_dir_entry->key);
00774        free(per_dir_entry->value);
00775 }
00776 /* }}} */
00777 
00778 /* {{{ copy_per_dir_entry
00779  */
00780 static void copy_per_dir_entry(php_per_dir_entry *per_dir_entry)
00781 {
00782        php_per_dir_entry tmp = *per_dir_entry;
00783 
00784        per_dir_entry->key = (char *) malloc(tmp.key_length+1);
00785        memcpy(per_dir_entry->key, tmp.key, tmp.key_length);
00786        per_dir_entry->key[per_dir_entry->key_length] = 0;
00787 
00788        per_dir_entry->value = (char *) malloc(tmp.value_length+1);
00789        memcpy(per_dir_entry->value, tmp.value, tmp.value_length);
00790        per_dir_entry->value[per_dir_entry->value_length] = 0;
00791 }
00792 /* }}} */
00793 
00794 /* {{{ should_overwrite_per_dir_entry;
00795 
00796  */
00797 static zend_bool should_overwrite_per_dir_entry(HashTable *target_ht, php_per_dir_entry *orig_per_dir_entry, zend_hash_key *hash_key, void *pData)
00798 {
00799        php_per_dir_entry *new_per_dir_entry;
00800 
00801        if (zend_hash_find(target_ht, hash_key->arKey, hash_key->nKeyLength, (void **) &new_per_dir_entry)==FAILURE) {
00802               return 1; /* does not exist in dest, copy from source */
00803        }
00804 
00805        if (new_per_dir_entry->type==PHP_INI_SYSTEM
00806               && orig_per_dir_entry->type!=PHP_INI_SYSTEM) {
00807               return 1;
00808        } else {
00809               return 0;
00810        }
00811 }
00812 /* }}} */
00813 /* {{{ php_destroy_per_server_info
00814  */
00815 static void php_destroy_per_server_info(php_per_server_config *conf)
00816 {
00817        php_handler_stack_destroy(&conf->requires);
00818        php_handler_stack_destroy(&conf->uri_handlers);
00819 }
00820 /* }}} */
00821 
00822 /* {{{ php_destroy_per_dir_info
00823  */
00824 static void php_destroy_per_dir_info(php_per_dir_config *conf) 
00825 {
00826        zend_hash_destroy(conf->ini_settings);
00827        php_handler_stack_destroy(&conf->response_handlers);
00828        php_handler_stack_destroy(&conf->auth_handlers);
00829        php_handler_stack_destroy(&conf->access_handlers);
00830        php_handler_stack_destroy(&conf->type_handlers);
00831        php_handler_stack_destroy(&conf->fixup_handlers);
00832        php_handler_stack_destroy(&conf->logger_handlers);
00833        php_handler_stack_destroy(&conf->post_read_handlers);
00834        php_handler_stack_destroy(&conf->headers_handlers);
00835        free(conf->ini_settings);
00836 }
00837 /* }}} */
00838 
00839 /* {{{ php_create_server
00840  */
00841 static void *php_create_server(pool *p, char *dummy)
00842 {
00843        php_per_server_config *conf;
00844        conf = (php_per_server_config *) malloc(sizeof(php_per_server_config));
00845        register_cleanup(p, (void *) conf, (void (*)(void *)) php_destroy_per_server_info, (void (*)(void *)) php_destroy_per_server_info);
00846        
00847        sapi_stack_init_ex(&conf->requires, 1);
00848        sapi_stack_init_ex(&conf->uri_handlers, 1);
00849        return conf;
00850 }
00851        
00852 /* }}} */
00853 
00854 
00855 /* {{{ php_create_dir
00856  */
00857 static void *php_create_dir(pool *p, char *dummy)
00858 {
00859        php_per_dir_config *conf;
00860        conf = (php_per_dir_config *) malloc(sizeof(php_per_dir_config));
00861        conf->ini_settings = (HashTable *) malloc(sizeof(HashTable));
00862        zend_hash_init_ex(conf->ini_settings, 5, NULL, (void (*)(void *)) destroy_per_dir_entry, 1, 0);
00863        sapi_stack_init_ex(&conf->response_handlers, 1);
00864        sapi_stack_init_ex(&conf->headers_handlers, 1);
00865        sapi_stack_init_ex(&conf->auth_handlers, 1);
00866        sapi_stack_init_ex(&conf->access_handlers, 1);
00867        sapi_stack_init_ex(&conf->type_handlers, 1);
00868        sapi_stack_init_ex(&conf->fixup_handlers, 1);
00869        sapi_stack_init_ex(&conf->logger_handlers, 1);
00870        sapi_stack_init_ex(&conf->post_read_handlers, 1);
00871        register_cleanup(p, (void *) conf, (void (*)(void *)) php_destroy_per_dir_info, (void (*)(void *)) php_destroy_per_dir_info);
00872        
00873        return conf;
00874 }
00875 
00876 /* }}} */
00877 
00878 /* {{{ php_merge_dir
00879  */
00880 static void *php_merge_dir(pool *p, void *basev, void *addv)
00881 {
00882        php_per_dir_config *a = (php_per_dir_config *) addv;
00883        php_per_dir_config *b = (php_per_dir_config *) basev;
00884        /* This function *must* return addv, and not modify basev */
00885        zend_hash_merge_ex((HashTable *) a->ini_settings, (HashTable *) b->ini_settings, (copy_ctor_func_t) copy_per_dir_entry, sizeof(php_per_dir_entry), (merge_checker_func_t) should_overwrite_per_dir_entry, NULL);
00886        a->headers_handlers = (a->headers_handlers.top)?a->headers_handlers:b->headers_handlers;
00887        a->auth_handlers = (a->auth_handlers.top)?a->auth_handlers:b->auth_handlers;
00888        a->access_handlers = (a->access_handlers.top)?a->access_handlers:b->access_handlers;
00889        a->type_handlers = (a->type_handlers.top)?a->type_handlers:b->type_handlers;
00890        a->fixup_handlers = (a->fixup_handlers.top)?a->fixup_handlers:b->fixup_handlers;
00891        a->logger_handlers = (a->logger_handlers.top)?a->logger_handlers:b->logger_handlers;
00892        a->post_read_handlers = (a->post_read_handlers.top)?a->post_read_handlers:b->post_read_handlers;
00893        a->response_handlers = (a->response_handlers.top)?a->response_handlers:b->response_handlers;
00894        return a;
00895 }
00896 /* }}} */
00897 
00898 /* {{{ php_apache_value_handler_ex
00899  */
00900 static CONST_PREFIX char *php_apache_value_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode)
00901 {
00902        php_per_dir_entry per_dir_entry;
00903 
00904        if (!apache_php_initialized) {
00905               apache_php_initialized = 1;
00906 #ifdef ZTS
00907               tsrm_startup(1, 1, 0, NULL);
00908 #endif
00909               sapi_startup(&apache_sapi_module);
00910               php_apache_startup(&apache_sapi_module);
00911        }
00912        per_dir_entry.type = mode;
00913 
00914        if (strcasecmp(arg2, "none") == 0) {
00915               arg2 = "";
00916        }
00917 
00918        per_dir_entry.key_length = strlen(arg1);
00919        per_dir_entry.value_length = strlen(arg2);
00920 
00921        per_dir_entry.key = (char *) malloc(per_dir_entry.key_length+1);
00922        memcpy(per_dir_entry.key, arg1, per_dir_entry.key_length);
00923        per_dir_entry.key[per_dir_entry.key_length] = 0;
00924 
00925        per_dir_entry.value = (char *) malloc(per_dir_entry.value_length+1);
00926        memcpy(per_dir_entry.value, arg2, per_dir_entry.value_length);
00927        per_dir_entry.value[per_dir_entry.value_length] = 0;
00928 
00929        zend_hash_update(conf, per_dir_entry.key, per_dir_entry.key_length, &per_dir_entry, sizeof(php_per_dir_entry), NULL);
00930        return NULL;
00931 }
00932 /* }}} */
00933 
00934 static CONST_PREFIX char *php_set_server_handler(server_rec *s, char *arg1, long handler_stage, long handler_type)
00935 {
00936        php_per_server_config *conf;
00937        php_handler *handler;
00938        handler = (php_handler *) malloc(sizeof(php_handler));
00939        handler->type = handler_type;
00940        handler->stage = handler_stage;
00941        handler->name = strdup(arg1);
00942        conf = get_module_config(s->module_config, &php5_module);
00943        switch(handler_stage) {
00944               case AP_URI_TRANS:
00945                      sapi_stack_push(&conf->uri_handlers, handler);
00946                      break;
00947               default:
00948                      sapi_stack_push(&conf->requires, handler);
00949                      break;
00950        }
00951        return NULL;
00952 }
00953 
00954 static CONST_PREFIX char *php_set_dir_handler(php_per_dir_config *conf, char *arg1, long handler_stage, long handler_type)
00955 {
00956        php_handler *handler;
00957        handler = (php_handler *) malloc(sizeof(php_handler));
00958        handler->type = handler_type;
00959        handler->stage = handler_stage;
00960        handler->name = strdup(arg1);
00961        switch(handler_stage) {
00962               case AP_POST_READ:
00963                      sapi_stack_push(&conf->post_read_handlers, handler);
00964                      break;
00965               case AP_HEADER_PARSE:
00966                      sapi_stack_push(&conf->headers_handlers, handler);
00967                      break;
00968               case AP_ACCESS_CONTROL:
00969                      sapi_stack_push(&conf->access_handlers, handler);
00970                      break;
00971               case AP_AUTHENTICATION:
00972                      sapi_stack_push(&conf->auth_handlers, handler);
00973                      break;
00974               case AP_AUTHORIZATION:
00975                      break;
00976               case AP_TYPE_CHECKING:
00977                      sapi_stack_push(&conf->type_handlers, handler);
00978                      break;
00979               case AP_FIXUP:
00980                      sapi_stack_push(&conf->fixup_handlers, handler);
00981                      break;
00982               case AP_RESPONSE:
00983                      sapi_stack_push(&conf->response_handlers, handler);
00984                      break;
00985               case AP_LOGGING:
00986                      sapi_stack_push(&conf->logger_handlers, handler);
00987                      break;
00988               default:
00989                      break;
00990        }
00991        return NULL;
00992 }
00993 
00994 /* {{{ php_set_uri_handler 
00995  */
00996 static CONST_PREFIX char *php_set_uri_handler(cmd_parms *cmd, void *dummy, char *arg1)
00997 {
00998        return php_set_server_handler(cmd->server, arg1, AP_URI_TRANS, AP_HANDLER_TYPE_FILE);
00999 }
01000 /* }}} */
01001 
01002 /* {{{ php_set_uri_handler_code */
01003 static CONST_PREFIX char *php_set_uri_handler_code(cmd_parms *cmd, void *dummy, char *arg1)
01004 {
01005        return php_set_server_handler(cmd->server, arg1, AP_URI_TRANS, AP_HANDLER_TYPE_METHOD);
01006 }
01007 /* }}} */
01008 
01009 /* {{{ php_set_header_handler
01010  */
01011 static CONST_PREFIX char *php_set_header_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01012 {
01013        return php_set_dir_handler(conf, arg1, AP_HEADER_PARSE, AP_HANDLER_TYPE_FILE);
01014 }
01015 static CONST_PREFIX char *php_set_header_handler_code(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01016 {
01017        return php_set_dir_handler(conf, arg1, AP_HEADER_PARSE, AP_HANDLER_TYPE_METHOD);
01018 }
01019 /* }}} */
01020 
01021 /* {{{ php_set_auth_handler 
01022  */
01023 static CONST_PREFIX char *php_set_auth_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01024 {
01025        return php_set_dir_handler(conf, arg1, AP_AUTHENTICATION, AP_HANDLER_TYPE_FILE);
01026 }
01027 static CONST_PREFIX char *php_set_auth_handler_code(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01028 {
01029        return php_set_dir_handler(conf, arg1, AP_AUTHENTICATION, AP_HANDLER_TYPE_METHOD);
01030 }
01031 
01032 /* }}} */
01033 
01034 /* {{{ php_set_access_handler
01035  */
01036 static CONST_PREFIX char *php_set_access_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01037 {
01038        return php_set_dir_handler(conf, arg1, AP_ACCESS_CONTROL, AP_HANDLER_TYPE_FILE);
01039 }
01040 static CONST_PREFIX char *php_set_access_handler_code(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01041 {
01042        return php_set_dir_handler(conf, arg1, AP_ACCESS_CONTROL, AP_HANDLER_TYPE_METHOD);
01043 }
01044 
01045 /* }}} */
01046 
01047 /* {{{ php_set_type_handler
01048  */
01049 static CONST_PREFIX char *php_set_type_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01050 {
01051        return php_set_dir_handler(conf, arg1, AP_TYPE_CHECKING, AP_HANDLER_TYPE_FILE);
01052 }
01053 static CONST_PREFIX char *php_set_type_handler_code(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01054 {
01055        return php_set_dir_handler(conf, arg1, AP_TYPE_CHECKING, AP_HANDLER_TYPE_METHOD);
01056 }
01057 
01058 /* }}} */
01059 
01060 /* {{{ php_set_fixup_handler
01061  */
01062 static CONST_PREFIX char *php_set_fixup_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01063 {
01064        return php_set_dir_handler(conf, arg1, AP_FIXUP, AP_HANDLER_TYPE_FILE);
01065 }
01066 static CONST_PREFIX char *php_set_fixup_handler_code(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01067 {
01068        return php_set_dir_handler(conf, arg1, AP_FIXUP, AP_HANDLER_TYPE_METHOD);
01069 }
01070 /* }}} */
01071 
01072 /* {{{ php_set_logger_handler
01073  */
01074 static CONST_PREFIX char *php_set_logger_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01075 {
01076        return php_set_dir_handler(conf, arg1, AP_LOGGING, AP_HANDLER_TYPE_FILE);
01077 }
01078 static CONST_PREFIX char *php_set_logger_handler_code(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01079 {
01080        return php_set_dir_handler(conf, arg1, AP_LOGGING, AP_HANDLER_TYPE_METHOD);
01081 }
01082 
01083 /* }}} */ 
01084 
01085 /* {{{ php_set_post_read_handler
01086  */
01087 static CONST_PREFIX char *php_set_post_read_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01088 {
01089        return php_set_dir_handler(conf, arg1, AP_POST_READ, AP_HANDLER_TYPE_FILE);
01090 }
01091 static CONST_PREFIX char *php_set_post_read_handler_code(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01092 {
01093        return php_set_dir_handler(conf, arg1, AP_POST_READ, AP_HANDLER_TYPE_METHOD);
01094 }
01095 
01096 
01097 /* }}} */
01098 
01099 /* {{{ php_set_require
01100  */
01101 
01102 static CONST_PREFIX char *php_set_require(cmd_parms *cmd, void *dummy, char *arg1)
01103 {
01104        return php_set_server_handler(cmd->server, arg1, 0, AP_HANDLER_TYPE_FILE);
01105 }
01106 /* }}} */
01107 
01108 /* {{{ php_set_response_handler
01109  */
01110 static CONST_PREFIX char *php_set_response_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01111 {
01112        return php_set_dir_handler(conf, arg1, AP_RESPONSE, AP_HANDLER_TYPE_FILE);
01113 }
01114 static CONST_PREFIX char *php_set_response_handler_code(cmd_parms *cmd, php_per_dir_config *conf, char *arg1)
01115 {
01116        return php_set_dir_handler(conf, arg1, AP_RESPONSE, AP_HANDLER_TYPE_METHOD);
01117 }
01118 /* }}} */
01119        
01120 /* {{{ php_apache_value_handler
01121  */
01122 static CONST_PREFIX char *php_apache_value_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1, char *arg2)
01123 {
01124        return php_apache_value_handler_ex(cmd, conf->ini_settings, arg1, arg2, PHP_INI_PERDIR);
01125 }
01126 /* }}} */
01127 
01128 /* {{{ php_apache_admin_value_handler
01129  */
01130 static CONST_PREFIX char *php_apache_admin_value_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1, char *arg2)
01131 {
01132        return php_apache_value_handler_ex(cmd, conf->ini_settings, arg1, arg2, PHP_INI_SYSTEM);
01133 }
01134 /* }}} */
01135 
01136 /* {{{ php_apache_flag_handler_ex
01137  */
01138 static CONST_PREFIX char *php_apache_flag_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode)
01139 {
01140        char bool_val[2];
01141 
01142        if (!strcasecmp(arg2, "On")) {
01143               bool_val[0] = '1';
01144        } else {
01145               bool_val[0] = '0';
01146        }
01147        bool_val[1] = 0;
01148        
01149        return php_apache_value_handler_ex(cmd, conf, arg1, bool_val, mode);
01150 }
01151 /* }}} */
01152 
01153 /* {{{ php_apache_flag_handler
01154  */
01155 static CONST_PREFIX char *php_apache_flag_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1, char *arg2)
01156 {
01157        return php_apache_flag_handler_ex(cmd, conf->ini_settings, arg1, arg2, PHP_INI_PERDIR);
01158 }
01159 /* }}} */
01160 
01161 /* {{{ php_apache_admin_flag_handler
01162  */
01163 static CONST_PREFIX char *php_apache_admin_flag_handler(cmd_parms *cmd, php_per_dir_config *conf, char *arg1, char *arg2)
01164 {
01165        return php_apache_flag_handler_ex(cmd, conf->ini_settings, arg1, arg2, PHP_INI_SYSTEM);
01166 }
01167 /* }}} */
01168 
01169 /* {{{ php_apache_phpini_set
01170  */
01171 static CONST_PREFIX char *php_apache_phpini_set(cmd_parms *cmd, HashTable *conf, char *arg)
01172 {
01173        if (apache_sapi_module.php_ini_path_override) {
01174               return "Only first PHPINIDir directive honored per configuration tree - subsequent ones ignored";
01175        }
01176        apache_sapi_module.php_ini_path_override = ap_server_root_relative(cmd->pool, arg);
01177        return NULL;
01178 }
01179 /* }}} */
01180 
01181 /* {{{ int php_xbithack_handler(request_rec * r)
01182  */
01183 static int php_xbithack_handler(request_rec * r)
01184 {
01185        php_per_dir_config *conf;
01186        TSRMLS_FETCH();
01187 
01188        if (!(r->finfo.st_mode & S_IXUSR)) {
01189               r->allowed |= (1 << METHODS) - 1;
01190               return DECLINED;
01191        }
01192        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01193        if (conf) {
01194               zend_hash_apply((HashTable *) conf->ini_settings, (apply_func_t) php_apache_alter_ini_entries TSRMLS_CC);
01195        }
01196        if(!AP(xbithack)) {
01197               r->allowed |= (1 << METHODS) - 1;
01198               zend_try {
01199                      zend_ini_deactivate(TSRMLS_C);
01200               } zend_end_try();
01201               return DECLINED;
01202        }
01203        return send_parsed_php(r);
01204 }
01205 /* }}} */
01206 
01207 /* {{{ apache_php_module_shutdown_wrapper
01208  */
01209 static void apache_php_module_shutdown_wrapper(void)
01210 {
01211        apache_php_initialized = 0;
01212        apache_sapi_module.shutdown(&apache_sapi_module);
01213 
01214 #if MODULE_MAGIC_NUMBER >= 19970728
01215        /* This function is only called on server exit if the apache API
01216         * child_exit handler exists, so shutdown globally 
01217         */
01218        sapi_shutdown();
01219 #endif
01220 
01221 #ifdef ZTS
01222        tsrm_shutdown();
01223 #endif
01224 }
01225 /* }}} */
01226 
01227 #if MODULE_MAGIC_NUMBER >= 19970728
01228 /* {{{ php_child_exit_handler
01229  */
01230 static void php_child_exit_handler(server_rec *s, pool *p)
01231 {
01232 /*     apache_php_initialized = 0; */
01233        apache_sapi_module.shutdown(&apache_sapi_module);
01234 
01235 #ifdef ZTS
01236        tsrm_shutdown();
01237 #endif
01238 }
01239 /* }}} */
01240 #endif
01241 
01242 /* {{{ void php_init_handler(server_rec *s, pool *p)
01243  */
01244 static void php_init_handler(server_rec *s, pool *p)
01245 {
01246        register_cleanup(p, NULL, (void (*)(void *))apache_php_module_shutdown_wrapper, (void (*)(void *))php_module_shutdown_for_exec);
01247        if (!apache_php_initialized) {
01248               apache_php_initialized = 1;
01249 #ifdef ZTS
01250               tsrm_startup(1, 1, 0, NULL);
01251 #endif
01252               sapi_startup(&apache_sapi_module);
01253               php_apache_startup(&apache_sapi_module);
01254        }
01255 #if MODULE_MAGIC_NUMBER >= 19980527
01256        {
01257               TSRMLS_FETCH();
01258               if (PG(expose_php)) {
01259                      ap_add_version_component("PHP/" PHP_VERSION);
01260               }
01261        }
01262 #endif
01263 }
01264 /* }}} */
01265 
01266 static int php_run_hook(php_handler *handler, request_rec *r)
01267 {
01268        zval *ret = NULL;
01269        php_per_dir_config *conf;
01270 
01271        TSRMLS_FETCH();
01272 
01273        if(!AP(apache_config_loaded)) {
01274               conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01275               if (conf)
01276                         zend_hash_apply((HashTable *)conf->ini_settings, (apply_func_t) php_apache_alter_ini_entries TSRMLS_CC);
01277               AP(apache_config_loaded) = 1;
01278        }
01279        if (!handler->name) {
01280               return DECLINED;
01281        }
01282        php_save_umask();
01283        if (!AP(setup_env)) {
01284               AP(setup_env) = 1;
01285               add_common_vars(r);
01286               add_cgi_vars(r);
01287        }
01288        SG(server_context) = r;
01289        init_request_info(TSRMLS_C);
01290        apache_php_module_hook(r, handler, &ret TSRMLS_CC);
01291        php_restore_umask();
01292        kill_timeout(r);
01293        if (ret) {
01294               convert_to_long(ret);
01295               return Z_LVAL_P(ret);
01296        }
01297        return HTTP_INTERNAL_SERVER_ERROR;
01298 }
01299  
01300 
01301 static int php_uri_translation(request_rec *r)
01302 {      
01303        php_per_server_config *conf;
01304        TSRMLS_FETCH();
01305        AP(current_hook) = AP_URI_TRANS;
01306        conf = (php_per_server_config *) get_module_config(r->server->module_config, &php5_module);
01307        return sapi_stack_apply_with_argument_stop_if_equals(&conf->uri_handlers, 
01308                      ZEND_STACK_APPLY_BOTTOMUP, 
01309                      (int (*)(void *element, void *)) php_run_hook, r, OK);
01310 }
01311 
01312 static int php_header_hook(request_rec *r)
01313 {
01314        php_per_dir_config *conf;
01315        TSRMLS_FETCH();
01316        AP(current_hook) = AP_HEADER_PARSE;
01317        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01318        return sapi_stack_apply_with_argument_stop_if_http_error(&conf->headers_handlers,
01319                      ZEND_STACK_APPLY_BOTTOMUP,
01320                      (int (*)(void *element, void *)) php_run_hook, r);
01321 }
01322 
01323 static int php_auth_hook(request_rec *r)
01324 {
01325        php_per_dir_config *conf;
01326        TSRMLS_FETCH();
01327        AP(current_hook) = AP_AUTHENTICATION;
01328        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01329        return sapi_stack_apply_with_argument_stop_if_equals(&conf->auth_handlers, 
01330                      ZEND_STACK_APPLY_BOTTOMUP, 
01331                      (int (*)(void *element, void *)) php_run_hook, r, OK);
01332 }
01333 
01334 static int php_access_hook(request_rec *r)
01335 {
01336        php_per_dir_config *conf;
01337        int status = DECLINED;
01338        TSRMLS_FETCH();
01339        AP(current_hook) = AP_ACCESS_CONTROL;
01340        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01341        status =  sapi_stack_apply_with_argument_stop_if_http_error(&conf->access_handlers,
01342                      ZEND_STACK_APPLY_BOTTOMUP,
01343                      (int (*)(void *element, void *)) php_run_hook, r);
01344        return status;
01345 
01346 }
01347 
01348 static int php_type_hook(request_rec *r)
01349 {
01350        php_per_dir_config *conf;
01351        TSRMLS_FETCH();
01352        AP(current_hook) = AP_TYPE_CHECKING;
01353        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01354        return sapi_stack_apply_with_argument_stop_if_equals(&conf->type_handlers,
01355                      ZEND_STACK_APPLY_BOTTOMUP,
01356                      (int (*)(void *element, void *)) php_run_hook,
01357                      r, OK);
01358 }
01359 
01360 static int php_fixup_hook(request_rec *r)
01361 {
01362        php_per_dir_config *conf;
01363        TSRMLS_FETCH();
01364        AP(current_hook) = AP_FIXUP;
01365        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01366        return sapi_stack_apply_with_argument_stop_if_http_error(&conf->fixup_handlers,
01367                      ZEND_STACK_APPLY_BOTTOMUP,
01368                      (int (*)(void *element, void *)) php_run_hook,
01369                      r);
01370 }
01371 
01372 static int php_logger_hook(request_rec *r)
01373 {
01374        php_per_dir_config *conf;
01375        TSRMLS_FETCH();
01376        AP(current_hook) = AP_LOGGING;
01377        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01378        return sapi_stack_apply_with_argument_stop_if_http_error(&conf->logger_handlers,
01379                      ZEND_STACK_APPLY_BOTTOMUP,
01380                      (int (*)(void *element, void *)) php_run_hook,
01381                      r);
01382 }
01383  
01384 static int php_post_read_hook(request_rec *r)
01385 {
01386        php_per_dir_config *conf;
01387        php_per_server_config *svr;
01388        TSRMLS_FETCH();
01389        AP(current_hook) = AP_POST_READ;
01390        svr = get_module_config(r->server->module_config, &php5_module);
01391        if(ap_is_initial_req(r)) {
01392               sapi_stack_apply_with_argument_all(&svr->requires, ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_run_hook, r);
01393        }
01394        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01395        return sapi_stack_apply_with_argument_stop_if_http_error(&conf->post_read_handlers,
01396                      ZEND_STACK_APPLY_BOTTOMUP,
01397                      (int (*)(void *element, void *)) php_run_hook, r);
01398 }
01399 
01400 static int php_response_handler(request_rec *r)
01401 {
01402        php_per_dir_config *conf;
01403        TSRMLS_FETCH();
01404        AP(current_hook) = AP_RESPONSE;
01405        conf = (php_per_dir_config *) get_module_config(r->per_dir_config, &php5_module);
01406        return sapi_stack_apply_with_argument_all(&conf->response_handlers, ZEND_STACK_APPLY_BOTTOMUP, (int (*)(void *element, void *)) php_run_hook, r);
01407 }
01408 
01409 /* {{{ handler_rec php_handlers[]
01410  */
01411 handler_rec php_handlers[] =
01412 {
01413        {"application/x-httpd-php", send_parsed_php},
01414        {"application/x-httpd-php-source", send_parsed_php_source},
01415        {"text/html", php_xbithack_handler},
01416               {"php-script", php_response_handler},
01417        {NULL}
01418 };
01419 /* }}} */
01420 
01421 /* {{{ command_rec php_commands[]
01422  */
01423 command_rec php_commands[] =
01424 {
01425        {"php_value",        php_apache_value_handler, NULL, OR_OPTIONS, TAKE2, "PHP Value Modifier"},
01426        {"phpUriHandler",           php_set_uri_handler, NULL, RSRC_CONF, TAKE1, "PHP Value Modifier"},
01427        {"phpUriHandlerMethod",            php_set_uri_handler_code, NULL, RSRC_CONF, TAKE1, "PHP Value Modifier"},
01428 #if MODULE_MAGIC_NUMBER >= 19970103
01429        {"phpHeaderHandler",        php_set_header_handler, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01430        {"phpHeaderHandlerMethod",         php_set_header_handler_code, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01431 #endif
01432        {"phpAuthHandler",          php_set_auth_handler, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01433        {"phpAuthHandlerMethod",           php_set_auth_handler_code, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01434        {"phpAccessHandler",        php_set_access_handler, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01435        {"phpAccessHandlerMethod",         php_set_access_handler_code, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01436        {"phpTypeHandler",          php_set_type_handler, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01437        {"phpTypeHandlerMethod",           php_set_type_handler_code, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01438        {"phpFixupHandler",         php_set_fixup_handler, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01439        {"phpFixupHandlerMethod",          php_set_fixup_handler_code, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01440        {"phpLoggerHandler",               php_set_logger_handler, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01441        {"phpLoggerHandlerMethod",         php_set_logger_handler_code, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01442 #if MODULE_MAGIC_NUMBER >= 19970902
01443        {"phpPostReadHandler",             php_set_post_read_handler, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01444        {"phpPostReadHandlerMethod",              php_set_post_read_handler_code, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01445        {"phpRequire",              php_set_require, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01446        {"phpResponseHandler",             php_set_response_handler, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01447        {"phpResponseHandlerMethod",              php_set_response_handler_code, NULL, OR_OPTIONS, TAKE1, "PHP Value Modifier"},
01448 #endif
01449        {"php_flag",         php_apache_flag_handler, NULL, OR_OPTIONS, TAKE2, "PHP Flag Modifier"},
01450        {"php_admin_value",  php_apache_admin_value_handler, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, "PHP Value Modifier (Admin)"},
01451        {"php_admin_flag",   php_apache_admin_flag_handler, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, "PHP Flag Modifier (Admin)"},
01452        {"PHPINIDir",       php_apache_phpini_set, NULL, RSRC_CONF, TAKE1, "Directory containing the php.ini file"},
01453        {NULL}
01454 };
01455 /* }}} */
01456 
01457 /* {{{ module MODULE_VAR_EXPORT php5_module
01458  */
01459 module MODULE_VAR_EXPORT php5_module =
01460 {
01461        STANDARD_MODULE_STUFF,
01462        php_init_handler,                  /* initializer */
01463        php_create_dir,                           /* per-directory config creator */
01464        php_merge_dir,                            /* dir merger */
01465        php_create_server,                 /* per-server config creator */
01466        NULL,                                     /* merge server config */
01467        php_commands,                      /* command table */
01468        php_handlers,                      /* handlers */
01469        php_uri_translation,        /* filename translation */
01470        NULL,                                     /* check_user_id */
01471        php_auth_hook,                            /* check auth */
01472        php_access_hook,                   /* check access */
01473        php_type_hook,                            /* type_checker */
01474        php_fixup_hook,                           /* fixups */
01475        php_logger_hook                           /* logger */
01476 #if MODULE_MAGIC_NUMBER >= 19970103
01477        , php_header_hook                                       /* header parser */
01478 #endif
01479 #if MODULE_MAGIC_NUMBER >= 19970719
01480        , NULL                                    /* child_init */
01481 #endif
01482 #if MODULE_MAGIC_NUMBER >= 19970728
01483        , php_child_exit_handler    /* child_exit */
01484 #endif
01485 #if MODULE_MAGIC_NUMBER >= 19970902
01486        , php_post_read_hook                                    /* post read-request */
01487 #endif
01488 };
01489 /* }}} */
01490 
01491 /*
01492  * Local variables:
01493  * tab-width: 4
01494  * c-basic-offset: 4
01495  * End:
01496  * vim600: sw=4 ts=4 fdm=marker
01497  * vim<600: sw=4 ts=4
01498  */