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 through the world-wide-web at the following url:           |
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 #include "http_conf_globals.h"
00024 
00025 #ifdef NETWARE
00026 #define SIGPIPE SIGINT
00027 #endif
00028 
00029 #undef shutdown
00030 
00031 /* {{{ Prototypes
00032  */
00033 int apache_php_module_main(request_rec *r, int display_source_mode TSRMLS_DC);
00034 static void php_save_umask(void);
00035 static void php_restore_umask(void);
00036 static int sapi_apache_read_post(char *buffer, uint count_bytes TSRMLS_DC);
00037 static char *sapi_apache_read_cookies(TSRMLS_D);
00038 static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
00039 static int sapi_apache_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC);
00040 static int send_php(request_rec *r, int display_source_mode, char *filename);
00041 static int send_parsed_php(request_rec * r);
00042 static int send_parsed_php_source(request_rec * r);
00043 static int php_xbithack_handler(request_rec * r);
00044 static void php_init_handler(server_rec *s, pool *p);
00045 /* }}} */
00046 
00047 #if MODULE_MAGIC_NUMBER >= 19970728
00048 static void php_child_exit_handler(server_rec *s, pool *p);
00049 #endif
00050 
00051 #if MODULE_MAGIC_NUMBER > 19961007
00052 #define CONST_PREFIX const
00053 #else
00054 #define CONST_PREFIX
00055 #endif
00056 static CONST_PREFIX char *php_apache_value_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode);
00057 static CONST_PREFIX char *php_apache_value_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2);
00058 static CONST_PREFIX char *php_apache_admin_value_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2);
00059 static CONST_PREFIX char *php_apache_flag_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2);
00060 static CONST_PREFIX char *php_apache_flag_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode);
00061 static CONST_PREFIX char *php_apache_admin_flag_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2);
00062 
00063 /* ### these should be defined in mod_php5.h or somewhere else */
00064 #define USE_PATH 1
00065 #define IGNORE_URL 2
00066 #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST POSSIBLE STATUS DESCRIPTION")
00067 
00068 module MODULE_VAR_EXPORT php5_module;
00069 
00070 int saved_umask;
00071 static unsigned char apache_php_initialized;
00072 
00073 typedef struct _php_per_dir_entry {
00074        char *key;
00075        char *value;
00076        uint key_length;
00077        uint value_length;
00078        int type;
00079        char htaccess;
00080 } php_per_dir_entry;
00081 
00082 /* some systems are missing these from their header files */
00083 
00084 /* {{{ php_save_umask
00085  */
00086 static void php_save_umask(void)
00087 {
00088        saved_umask = umask(077);
00089        umask(saved_umask);
00090 }
00091 /* }}} */
00092 
00093 /* {{{ sapi_apache_ub_write
00094  */
00095 static int sapi_apache_ub_write(const char *str, uint str_length TSRMLS_DC)
00096 {
00097        int ret=0;
00098               
00099        if (SG(server_context)) {
00100               ret = rwrite(str, str_length, (request_rec *) SG(server_context));
00101        }
00102        if (ret != str_length) {
00103               php_handle_aborted_connection();
00104        }
00105        return ret;
00106 }
00107 /* }}} */
00108 
00109 /* {{{ sapi_apache_flush
00110  */
00111 static void sapi_apache_flush(void *server_context)
00112 {
00113        if (server_context) {
00114 #if MODULE_MAGIC_NUMBER > 19970110
00115               rflush((request_rec *) server_context);
00116 #else
00117               bflush((request_rec *) server_context->connection->client);
00118 #endif
00119        }
00120 }
00121 /* }}} */
00122 
00123 /* {{{ sapi_apache_read_post
00124  */
00125 static int sapi_apache_read_post(char *buffer, uint count_bytes TSRMLS_DC)
00126 {
00127        int total_read_bytes=0, read_bytes;
00128        request_rec *r = (request_rec *) SG(server_context);
00129        void (*handler)(int);
00130 
00131        /*
00132         * This handles the situation where the browser sends a Expect: 100-continue header
00133         * and needs to recieve confirmation from the server on whether or not it can send
00134         * the rest of the request. RFC 2616
00135         *
00136         */
00137        if (!SG(read_post_bytes) && !ap_should_client_block(r)) {
00138               return total_read_bytes;
00139        }
00140  
00141        handler = signal(SIGPIPE, SIG_IGN);
00142        while (total_read_bytes<count_bytes) {
00143               hard_timeout("Read POST information", r); /* start timeout timer */
00144               read_bytes = get_client_block(r, buffer+total_read_bytes, count_bytes-total_read_bytes);
00145               reset_timeout(r);
00146               if (read_bytes<=0) {
00147                      break;
00148               }
00149               total_read_bytes += read_bytes;
00150        }
00151        signal(SIGPIPE, handler);   
00152        return total_read_bytes;
00153 }
00154 /* }}} */
00155 
00156 /* {{{ sapi_apache_read_cookies
00157  */
00158 static char *sapi_apache_read_cookies(TSRMLS_D)
00159 {
00160        return (char *) table_get(((request_rec *) SG(server_context))->subprocess_env, "HTTP_COOKIE");
00161 }
00162 /* }}} */
00163 
00164 /* {{{ sapi_apache_header_handler
00165  */
00166 static int sapi_apache_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
00167 {
00168        char *header_name, *header_content, *p;
00169        request_rec *r = (request_rec *) SG(server_context);
00170        if(!r) {
00171               return 0;
00172        }
00173 
00174        switch(op) {
00175               case SAPI_HEADER_DELETE_ALL:
00176                      clear_table(r->headers_out);
00177                      return 0;
00178 
00179               case SAPI_HEADER_DELETE:
00180                      table_unset(r->headers_out, sapi_header->header);
00181                      return 0;
00182 
00183               case SAPI_HEADER_ADD:
00184               case SAPI_HEADER_REPLACE:
00185                      header_name = sapi_header->header;
00186 
00187                      header_content = p = strchr(header_name, ':');
00188                      if (!p) {
00189                             return 0;
00190                      }
00191 
00192                      *p = 0;
00193                      do {
00194                             header_content++;
00195                      } while (*header_content==' ');
00196 
00197                      if (!strcasecmp(header_name, "Content-Type")) {
00198                             r->content_type = pstrdup(r->pool, header_content);
00199                        } else if (!strcasecmp(header_name, "Content-Length")) {
00200                                ap_set_content_length(r, strtol(header_content, (char **)NULL, 10));
00201                      } else if (!strcasecmp(header_name, "Set-Cookie")) {
00202                             table_add(r->headers_out, header_name, header_content);
00203                      } else if (op == SAPI_HEADER_REPLACE) {
00204                             table_set(r->headers_out, header_name, header_content);
00205                      } else {
00206                             table_add(r->headers_out, header_name, header_content);
00207                      }
00208 
00209                      *p = ':';  /* a well behaved header handler shouldn't change its original arguments */
00210 
00211                      return SAPI_HEADER_ADD;
00212 
00213               default:
00214                      return 0;
00215        }
00216 }
00217 /* }}} */
00218 
00219 /* {{{ sapi_apache_send_headers
00220  */
00221 static int sapi_apache_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00222 {
00223        request_rec *r = SG(server_context);
00224        const char *sline = SG(sapi_headers).http_status_line;
00225        int sline_len;
00226 
00227        if(r == NULL) { /* server_context is not here anymore */
00228               return SAPI_HEADER_SEND_FAILED;
00229        }
00230 
00231        r->status = SG(sapi_headers).http_response_code;
00232 
00233        /* httpd requires that r->status_line is set to the first digit of
00234         * the status-code: */
00235        if (sline && ((sline_len = strlen(sline)) > 12) && strncmp(sline, "HTTP/1.", 7) == 0 && sline[8] == ' ' && sline[12] == ' ') {
00236               if ((sline_len - 9) > MAX_STATUS_LENGTH) {
00237                      r->status_line = ap_pstrndup(r->pool, sline + 9, MAX_STATUS_LENGTH);
00238               } else {
00239                      r->status_line = ap_pstrndup(r->pool, sline + 9, sline_len - 9);
00240               }
00241        }
00242 
00243        if(r->status==304) {
00244               send_error_response(r,0);
00245        } else {
00246               send_http_header(r);
00247        }
00248        return SAPI_HEADER_SENT_SUCCESSFULLY;
00249 }
00250 /* }}} */
00251 
00252 /* {{{ sapi_apache_register_server_variables
00253  */
00254 static void sapi_apache_register_server_variables(zval *track_vars_array TSRMLS_DC)
00255 {
00256        register int i;
00257        array_header *arr = table_elts(((request_rec *) SG(server_context))->subprocess_env);
00258        table_entry *elts = (table_entry *) arr->elts;
00259        zval **path_translated;
00260        HashTable *symbol_table;
00261        unsigned int new_val_len;
00262 
00263        for (i = 0; i < arr->nelts; i++) {
00264               char *val;
00265               int val_len;
00266 
00267               if (elts[i].val) {
00268                      val = elts[i].val;
00269               } else {
00270                      val = "";
00271               }
00272               val_len = strlen(val);
00273               if (sapi_module.input_filter(PARSE_SERVER, elts[i].key, &val, val_len, &new_val_len TSRMLS_CC)) {
00274                      php_register_variable_safe(elts[i].key, val, new_val_len, track_vars_array TSRMLS_CC);
00275               }
00276        }
00277 
00278        /* If PATH_TRANSLATED doesn't exist, copy it from SCRIPT_FILENAME */
00279        if (track_vars_array) {
00280               symbol_table = track_vars_array->value.ht;
00281        } else if (PG(register_globals)) {
00282               /* should never happen nowadays */
00283               symbol_table = EG(active_symbol_table);
00284        } else {
00285               symbol_table = NULL;
00286        }
00287        if (symbol_table
00288               && !zend_hash_exists(symbol_table, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED"))
00289               && zend_hash_find(symbol_table, "SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME"), (void **) &path_translated)==SUCCESS) {
00290               php_register_variable("PATH_TRANSLATED", Z_STRVAL_PP(path_translated), track_vars_array TSRMLS_CC);
00291        }
00292 
00293        if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &((request_rec *) SG(server_context))->uri, strlen(((request_rec *) SG(server_context))->uri), &new_val_len TSRMLS_CC)) {
00294               php_register_variable("PHP_SELF", ((request_rec *) SG(server_context))->uri, track_vars_array TSRMLS_CC);
00295        }
00296 }
00297 /* }}} */
00298 
00299 /* {{{ php_apache_startup
00300  */
00301 static int php_apache_startup(sapi_module_struct *sapi_module)
00302 {
00303        if (php_module_startup(sapi_module, &apache_module_entry, 1) == FAILURE) {
00304               return FAILURE;
00305        } else {
00306               return SUCCESS;
00307        }
00308 }
00309 /* }}} */
00310 
00311 /* {{{ php_apache_log_message
00312  */
00313 static void php_apache_log_message(char *message)
00314 {
00315        TSRMLS_FETCH();
00316 
00317        if (SG(server_context)) {
00318 #if MODULE_MAGIC_NUMBER >= 19970831
00319               aplog_error(NULL, 0, APLOG_ERR | APLOG_NOERRNO, ((request_rec *) SG(server_context))->server, "%s", message);
00320 #else
00321               log_error(message, ((request_rec *) SG(server_context))->server);
00322 #endif
00323        } else {
00324               fprintf(stderr, "%s\n", message);
00325        }
00326 }
00327 /* }}} */
00328 
00329 /* {{{ php_apache_request_shutdown
00330  */
00331 static void php_apache_request_shutdown(void *dummy)
00332 {
00333        TSRMLS_FETCH();
00334 
00335        php_output_set_status(0 TSRMLS_CC);
00336        if (AP(in_request)) {
00337               AP(in_request) = 0;
00338               php_request_shutdown(dummy);
00339        }
00340        SG(server_context) = NULL; 
00341        /* 
00342        * The server context (request) is NOT invalid by the time 
00343        * run_cleanups() is called 
00344        */
00345 }
00346 /* }}} */
00347 
00348 /* {{{ php_apache_sapi_activate
00349  */
00350 static int php_apache_sapi_activate(TSRMLS_D)
00351 {
00352        request_rec *r = (request_rec *) SG(server_context); 
00353 
00354        /*
00355         * For the Apache module version, this bit of code registers a cleanup
00356         * function that gets triggered when our request pool is destroyed.
00357         * We need this because at any point in our code we can be interrupted
00358         * and that may happen before we have had time to free our memory.
00359         * The php_request_shutdown function needs to free all outstanding allocated
00360         * memory.  
00361         */
00362        block_alarms();
00363        register_cleanup(r->pool, NULL, php_apache_request_shutdown, php_request_shutdown_for_exec);
00364        AP(in_request)=1;
00365        unblock_alarms();
00366 
00367        /* Override the default headers_only value - sometimes "GET" requests should actually only
00368         * send headers.
00369         */
00370        SG(request_info).headers_only = r->header_only;
00371        return SUCCESS;
00372 }
00373 /* }}} */
00374 
00375 /* {{{ php_apache_get_stat
00376  */
00377 static struct stat *php_apache_get_stat(TSRMLS_D)
00378 {
00379        return &((request_rec *) SG(server_context))->finfo;
00380 }
00381 /* }}} */
00382 
00383 /* {{{ php_apache_getenv
00384  */
00385 static char *php_apache_getenv(char *name, size_t name_len TSRMLS_DC)
00386 {
00387        if (SG(server_context) == NULL) {
00388               return NULL;
00389        }
00390 
00391        return (char *) table_get(((request_rec *) SG(server_context))->subprocess_env, name);
00392 }
00393 /* }}} */
00394 
00395 /* {{{ sapi_apache_get_fd
00396  */
00397 static int sapi_apache_get_fd(int *nfd TSRMLS_DC)
00398 {
00399 #if PHP_APACHE_HAVE_CLIENT_FD
00400        request_rec *r = SG(server_context);
00401        int fd;
00402 
00403        fd = r->connection->client->fd;
00404        
00405        if (fd >= 0) {
00406               if (nfd) *nfd = fd;
00407               return SUCCESS;
00408        }
00409 #endif
00410        return FAILURE;
00411 }
00412 /* }}} */
00413 
00414 /* {{{ sapi_apache_force_http_10
00415  */
00416 static int sapi_apache_force_http_10(TSRMLS_D)
00417 {
00418        request_rec *r = SG(server_context);
00419        
00420        r->proto_num = HTTP_VERSION(1,0);
00421        
00422        return SUCCESS;
00423 }
00424 /* }}} */
00425 
00426 /* {{{ sapi_apache_get_target_uid
00427  */
00428 static int sapi_apache_get_target_uid(uid_t *obj TSRMLS_DC)
00429 {
00430        *obj = ap_user_id;
00431        return SUCCESS;
00432 }
00433 /* }}} */
00434 
00435 /* {{{ sapi_apache_get_target_gid
00436  */
00437 static int sapi_apache_get_target_gid(gid_t *obj TSRMLS_DC)
00438 {
00439        *obj = ap_group_id;
00440        return SUCCESS;
00441 }
00442 /* }}} */
00443 
00444 /* {{{ php_apache_get_request_time
00445  */
00446 static time_t php_apache_get_request_time(TSRMLS_D)
00447 {
00448        return ((request_rec *)SG(server_context))->request_time;
00449 }
00450 /* }}} */
00451 
00452 /* {{{ sapi_apache_child_terminate
00453  */
00454 static void sapi_apache_child_terminate(TSRMLS_D)
00455 {
00456 #ifndef MULTITHREAD
00457        ap_child_terminate((request_rec *)SG(server_context));
00458 #endif
00459 }
00460 /* }}} */
00461 
00462 /* {{{ sapi_module_struct apache_sapi_module
00463  */
00464 static sapi_module_struct apache_sapi_module = {
00465        "apache",                                        /* name */
00466        "Apache",                                        /* pretty name */
00467                                                                
00468        php_apache_startup,                       /* startup */
00469        php_module_shutdown_wrapper,       /* shutdown */
00470 
00471        php_apache_sapi_activate,          /* activate */
00472        NULL,                                            /* deactivate */
00473 
00474        sapi_apache_ub_write,                     /* unbuffered write */
00475        sapi_apache_flush,                        /* flush */
00476        php_apache_get_stat,               /* get uid */
00477        php_apache_getenv,                        /* getenv */
00478 
00479        php_error,                                       /* error handler */
00480 
00481        sapi_apache_header_handler,        /* header handler */
00482        sapi_apache_send_headers,          /* send headers handler */
00483        NULL,                                            /* send header handler */
00484 
00485        sapi_apache_read_post,                    /* read POST data */
00486        sapi_apache_read_cookies,          /* read Cookies */
00487 
00488        sapi_apache_register_server_variables,           /* register server variables */
00489        php_apache_log_message,                   /* Log message */
00490        php_apache_get_request_time,       /* Get request time */
00491        sapi_apache_child_terminate,
00492 
00493        NULL,                                            /* php.ini path override */
00494 
00495 #ifdef PHP_WIN32
00496        NULL,
00497        NULL,
00498 #else
00499        block_alarms,                             /* Block interruptions */
00500        unblock_alarms,                                  /* Unblock interruptions */
00501 #endif
00502 
00503        NULL,                                            /* default post reader */
00504        NULL,                                            /* treat data */
00505        NULL,                                            /* exe location */
00506        0,                                                      /* ini ignore */
00507        sapi_apache_get_fd,
00508        sapi_apache_force_http_10,
00509        sapi_apache_get_target_uid,
00510        sapi_apache_get_target_gid
00511 };
00512 /* }}} */
00513 
00514 /* {{{ php_restore_umask
00515  */
00516 static void php_restore_umask(void)
00517 {
00518        umask(saved_umask);
00519 }
00520 /* }}} */
00521 
00522 /* {{{ init_request_info
00523  */
00524 static void init_request_info(TSRMLS_D)
00525 {
00526        request_rec *r = ((request_rec *) SG(server_context));
00527        char *content_length = (char *) table_get(r->subprocess_env, "CONTENT_LENGTH");
00528        const char *authorization=NULL;
00529        char *tmp, *tmp_user;
00530 
00531        SG(request_info).query_string = r->args;
00532        SG(request_info).path_translated = r->filename;
00533        SG(request_info).request_uri = r->uri;
00534        SG(request_info).request_method = (char *)r->method;
00535        SG(request_info).content_type = (char *) table_get(r->subprocess_env, "CONTENT_TYPE");
00536        SG(request_info).content_length = (content_length ? atol(content_length) : 0);
00537        SG(sapi_headers).http_response_code = r->status;
00538        SG(request_info).proto_num = r->proto_num;
00539 
00540        if (r->headers_in) {
00541               authorization = table_get(r->headers_in, "Authorization");
00542        }
00543 
00544        SG(request_info).auth_user = NULL;
00545        SG(request_info).auth_password = NULL;
00546        SG(request_info).auth_digest = NULL;
00547 
00548        if (authorization && (!PG(safe_mode) || (PG(safe_mode) && !auth_type(r)))) {
00549               char *p = getword(r->pool, &authorization, ' ');
00550               if (!strcasecmp(p, "Basic")) {
00551                      tmp = uudecode(r->pool, authorization);
00552                      tmp_user = getword_nulls_nc(r->pool, &tmp, ':');
00553                      if (tmp_user) {
00554                             r->connection->user = pstrdup(r->connection->pool, tmp_user);
00555                             r->connection->ap_auth_type = "Basic";
00556                             SG(request_info).auth_user = estrdup(tmp_user);
00557                      }
00558                      if (tmp) {
00559                             SG(request_info).auth_password = estrdup(tmp);
00560                      }
00561               } else if (!strcasecmp(p, "Digest")) {
00562                      r->connection->ap_auth_type = "Digest";
00563                      SG(request_info).auth_digest = estrdup(authorization);
00564               }
00565        }
00566 }
00567 /* }}} */
00568 
00569 /* {{{ php_apache_alter_ini_entries
00570  */
00571 static int php_apache_alter_ini_entries(php_per_dir_entry *per_dir_entry TSRMLS_DC)
00572 {
00573        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, per_dir_entry->htaccess?PHP_INI_STAGE_HTACCESS:PHP_INI_STAGE_ACTIVATE);
00574        return 0;
00575 }
00576 /* }}} */
00577 
00578 /* {{{ php_apache_get_default_mimetype
00579  */
00580 static char *php_apache_get_default_mimetype(request_rec *r TSRMLS_DC)
00581 {
00582        
00583        char *mimetype;
00584        if (SG(default_mimetype) || SG(default_charset)) {
00585               /* Assume output will be of the default MIME type.  Individual
00586                  scripts may change this later. */
00587               char *tmpmimetype;
00588               tmpmimetype = sapi_get_default_content_type(TSRMLS_C);
00589               mimetype = pstrdup(r->pool, tmpmimetype);
00590               efree(tmpmimetype);
00591        } else {
00592               mimetype = SAPI_DEFAULT_MIMETYPE "; charset=" SAPI_DEFAULT_CHARSET;
00593        }
00594        return mimetype;
00595 }
00596 /* }}} */
00597 
00598 /* {{{ send_php
00599  */
00600 static int send_php(request_rec *r, int display_source_mode, char *filename)
00601 {
00602        int retval;
00603        HashTable *per_dir_conf;
00604        TSRMLS_FETCH();
00605 
00606        if (AP(in_request)) {
00607               zend_file_handle fh;
00608 
00609               fh.filename = r->filename;
00610               fh.opened_path = NULL;
00611               fh.free_filename = 0;
00612               fh.type = ZEND_HANDLE_FILENAME;
00613 
00614               zend_execute_scripts(ZEND_INCLUDE TSRMLS_CC, NULL, 1, &fh);
00615               return OK;
00616        }
00617 
00618        SG(server_context) = r;
00619 
00620        zend_first_try {
00621 
00622               /* Make sure file exists */
00623               if (filename == NULL && r->finfo.st_mode == 0) {
00624                      return DECLINED;
00625               }
00626 
00627               per_dir_conf = (HashTable *) get_module_config(r->per_dir_config, &php5_module);
00628               if (per_dir_conf) {
00629                      zend_hash_apply((HashTable *) per_dir_conf, (apply_func_t) php_apache_alter_ini_entries TSRMLS_CC);
00630               }
00631               
00632               /* If PHP parser engine has been turned off with an "engine off"
00633                * directive, then decline to handle this request
00634                */
00635               if (!AP(engine)) {
00636                      r->content_type = php_apache_get_default_mimetype(r TSRMLS_CC);
00637                      zend_try {
00638                             zend_ini_deactivate(TSRMLS_C);
00639                      } zend_end_try();
00640                      return DECLINED;
00641               }
00642               if (filename == NULL) {
00643                      filename = r->filename;
00644               }
00645 
00646               /* Apache 1.2 has a more complex mechanism for reading POST data */
00647 #if MODULE_MAGIC_NUMBER > 19961007
00648               if ((retval = setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) {
00649                      zend_try {
00650                             zend_ini_deactivate(TSRMLS_C);
00651                      } zend_end_try();
00652                      return retval;
00653               }
00654 #endif
00655 
00656               if (AP(last_modified)) {
00657 #if MODULE_MAGIC_NUMBER < 19970912
00658                      if ((retval = set_last_modified(r, r->finfo.st_mtime))) {
00659                             zend_try {
00660                                    zend_ini_deactivate(TSRMLS_C);
00661                             } zend_end_try();
00662                             return retval;
00663                      }
00664 #else
00665                      update_mtime (r, r->finfo.st_mtime);
00666                      set_last_modified(r);
00667                      set_etag(r);
00668 #endif
00669               }
00670               /* Assume output will be of the default MIME type.  Individual
00671                  scripts may change this later in the request. */
00672               r->content_type = php_apache_get_default_mimetype(r TSRMLS_CC);
00673 
00674               /* Init timeout */
00675               hard_timeout("send", r);
00676 
00677               php_save_umask();
00678               add_common_vars(r);
00679               add_cgi_vars(r);
00680 
00681               init_request_info(TSRMLS_C);
00682               apache_php_module_main(r, display_source_mode TSRMLS_CC);
00683 
00684               /* Done, restore umask, turn off timeout, close file and return */
00685               php_restore_umask();
00686               kill_timeout(r);
00687        } zend_end_try();
00688 
00689        return OK;
00690 }
00691 /* }}} */
00692 
00693 /* {{{ send_parsed_php
00694  */
00695 static int send_parsed_php(request_rec * r)
00696 {
00697        int result = send_php(r, 0, NULL);
00698        TSRMLS_FETCH();
00699  
00700        ap_table_setn(r->notes, "mod_php_memory_usage",
00701               ap_psprintf(r->pool, "%lu", zend_memory_peak_usage(1 TSRMLS_CC)));
00702 
00703        return result;
00704 }
00705 /* }}} */
00706 
00707 /* {{{ send_parsed_php_source
00708  */
00709 static int send_parsed_php_source(request_rec * r)
00710 {
00711        return send_php(r, 1, NULL);
00712 }
00713 /* }}} */
00714 
00715 /* {{{ destroy_per_dir_entry
00716  */
00717 static void destroy_per_dir_entry(php_per_dir_entry *per_dir_entry)
00718 {
00719        free(per_dir_entry->key);
00720        free(per_dir_entry->value);
00721 }
00722 /* }}} */
00723 
00724 /* {{{ copy_per_dir_entry
00725  */
00726 static void copy_per_dir_entry(php_per_dir_entry *per_dir_entry)
00727 {
00728        php_per_dir_entry tmp = *per_dir_entry;
00729 
00730        per_dir_entry->key = (char *) malloc(tmp.key_length+1);
00731        memcpy(per_dir_entry->key, tmp.key, tmp.key_length);
00732        per_dir_entry->key[per_dir_entry->key_length] = 0;
00733 
00734        per_dir_entry->value = (char *) malloc(tmp.value_length+1);
00735        memcpy(per_dir_entry->value, tmp.value, tmp.value_length);
00736        per_dir_entry->value[per_dir_entry->value_length] = 0;
00737 }
00738 /* }}} */
00739 
00740 /* {{{ should_overwrite_per_dir_entry
00741  */
00742 static zend_bool should_overwrite_per_dir_entry(HashTable *target_ht, php_per_dir_entry *new_per_dir_entry, zend_hash_key *hash_key, void *pData)
00743 {
00744        php_per_dir_entry *orig_per_dir_entry;
00745 
00746        if (zend_hash_find(target_ht, hash_key->arKey, hash_key->nKeyLength, (void **) &orig_per_dir_entry)==FAILURE) {
00747               return 1; /* does not exist in dest, copy from source */
00748        }
00749 
00750        if (orig_per_dir_entry->type==PHP_INI_SYSTEM
00751               && new_per_dir_entry->type!=PHP_INI_SYSTEM) {
00752               return 0;
00753        } else {
00754               return 1;
00755        }
00756 }
00757 /* }}} */
00758 
00759 /* {{{ php_destroy_per_dir_info
00760  */
00761 static void php_destroy_per_dir_info(HashTable *per_dir_info)
00762 {
00763        zend_hash_destroy(per_dir_info);
00764        free(per_dir_info);
00765 }
00766 /* }}} */
00767 
00768 /* {{{ php_create_dir
00769  */
00770 static void *php_create_dir(pool *p, char *dummy)
00771 {
00772        HashTable *per_dir_info;
00773 
00774        per_dir_info = (HashTable *) malloc(sizeof(HashTable));
00775        zend_hash_init_ex(per_dir_info, 5, NULL, (void (*)(void *)) destroy_per_dir_entry, 1, 0);
00776        register_cleanup(p, (void *) per_dir_info, (void (*)(void *)) php_destroy_per_dir_info, (void (*)(void *)) zend_hash_destroy);
00777 
00778        return per_dir_info;
00779 }
00780 /* }}} */
00781 
00782 /* {{{ php_merge_dir
00783  */
00784 static void *php_merge_dir(pool *p, void *basev, void *addv)
00785 {
00786        /* This function *must* not modify addv or basev */
00787        HashTable *new;
00788 
00789        /* need a copy of addv to merge */
00790        new = php_create_dir(p, "php_merge_dir");
00791        zend_hash_copy(new, (HashTable *) basev, (copy_ctor_func_t) copy_per_dir_entry, NULL, sizeof(php_per_dir_entry));
00792 
00793        zend_hash_merge_ex(new, (HashTable *) addv, (copy_ctor_func_t) copy_per_dir_entry, sizeof(php_per_dir_entry), (merge_checker_func_t) should_overwrite_per_dir_entry, NULL);
00794        return new;
00795 }
00796 /* }}} */
00797 
00798 /* {{{ php_apache_value_handler_ex
00799  */
00800 static CONST_PREFIX char *php_apache_value_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode)
00801 {
00802        php_per_dir_entry per_dir_entry;
00803 
00804        if (!apache_php_initialized) {
00805               apache_php_initialized = 1;
00806 #ifdef ZTS
00807               tsrm_startup(1, 1, 0, NULL);
00808 #endif
00809               sapi_startup(&apache_sapi_module);
00810               php_apache_startup(&apache_sapi_module);
00811        }
00812        per_dir_entry.type = mode;
00813        per_dir_entry.htaccess = ((cmd->override & (RSRC_CONF|ACCESS_CONF)) == 0);
00814 
00815        if (strcasecmp(arg2, "none") == 0) {
00816               arg2 = "";
00817        }
00818 
00819        per_dir_entry.key_length = strlen(arg1);
00820        per_dir_entry.value_length = strlen(arg2);
00821 
00822        per_dir_entry.key = (char *) malloc(per_dir_entry.key_length+1);
00823        memcpy(per_dir_entry.key, arg1, per_dir_entry.key_length);
00824        per_dir_entry.key[per_dir_entry.key_length] = 0;
00825 
00826        per_dir_entry.value = (char *) malloc(per_dir_entry.value_length+1);
00827        memcpy(per_dir_entry.value, arg2, per_dir_entry.value_length);
00828        per_dir_entry.value[per_dir_entry.value_length] = 0;
00829 
00830        zend_hash_update(conf, per_dir_entry.key, per_dir_entry.key_length, &per_dir_entry, sizeof(php_per_dir_entry), NULL);
00831        return NULL;
00832 }
00833 /* }}} */
00834 
00835 /* {{{ php_apache_value_handler
00836  */
00837 static CONST_PREFIX char *php_apache_value_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2)
00838 {
00839        return php_apache_value_handler_ex(cmd, conf, arg1, arg2, PHP_INI_PERDIR);
00840 }
00841 /* }}} */
00842 
00843 /* {{{ php_apache_admin_value_handler
00844  */
00845 static CONST_PREFIX char *php_apache_admin_value_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2)
00846 {
00847        return php_apache_value_handler_ex(cmd, conf, arg1, arg2, PHP_INI_SYSTEM);
00848 }
00849 /* }}} */
00850 
00851 /* {{{ php_apache_flag_handler_ex
00852  */
00853 static CONST_PREFIX char *php_apache_flag_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode)
00854 {
00855        char bool_val[2];
00856 
00857        if (!strcasecmp(arg2, "On") || (arg2[0] == '1' && arg2[1] == '\0')) {
00858               bool_val[0] = '1';
00859        } else {
00860               bool_val[0] = '0';
00861        }
00862        bool_val[1] = 0;
00863        
00864        return php_apache_value_handler_ex(cmd, conf, arg1, bool_val, mode);
00865 }
00866 /* }}} */
00867 
00868 /* {{{ php_apache_flag_handler
00869  */
00870 static CONST_PREFIX char *php_apache_flag_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2)
00871 {
00872        return php_apache_flag_handler_ex(cmd, conf, arg1, arg2, PHP_INI_PERDIR);
00873 }
00874 /* }}} */
00875 
00876 /* {{{ php_apache_admin_flag_handler
00877  */
00878 static CONST_PREFIX char *php_apache_admin_flag_handler(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2)
00879 {
00880        return php_apache_flag_handler_ex(cmd, conf, arg1, arg2, PHP_INI_SYSTEM);
00881 }
00882 /* }}} */
00883 
00884 /* {{{ php_apache_phpini_set
00885  */
00886 static CONST_PREFIX char *php_apache_phpini_set(cmd_parms *cmd, HashTable *conf, char *arg)
00887 {
00888        if (apache_sapi_module.php_ini_path_override) {
00889               return "Only first PHPINIDir directive honored per configuration tree - subsequent ones ignored";
00890        }
00891        apache_sapi_module.php_ini_path_override = ap_server_root_relative(cmd->pool, arg);
00892        return NULL;
00893 }
00894 /* }}} */
00895 
00896 /* {{{ int php_xbithack_handler(request_rec * r)
00897  */
00898 static int php_xbithack_handler(request_rec * r)
00899 {
00900        HashTable *per_dir_conf;
00901        TSRMLS_FETCH();
00902 
00903        if (!(r->finfo.st_mode & S_IXUSR)) {
00904               return DECLINED;
00905        }
00906        per_dir_conf = (HashTable *) get_module_config(r->per_dir_config, &php5_module);
00907        if (per_dir_conf) {
00908               zend_hash_apply((HashTable *) per_dir_conf, (apply_func_t) php_apache_alter_ini_entries TSRMLS_CC);
00909        }
00910        if(!AP(xbithack)) {
00911               zend_try {
00912                      zend_ini_deactivate(TSRMLS_C);
00913               } zend_end_try();
00914               return DECLINED;
00915        }
00916        return send_parsed_php(r);
00917 }
00918 /* }}} */
00919 
00920 /* {{{ apache_php_module_shutdown_wrapper
00921  */
00922 static void apache_php_module_shutdown_wrapper(void)
00923 {
00924        apache_php_initialized = 0;
00925        apache_sapi_module.shutdown(&apache_sapi_module);
00926 
00927 #if MODULE_MAGIC_NUMBER >= 19970728
00928        /* This function is only called on server exit if the apache API
00929         * child_exit handler exists, so shutdown globally 
00930         */
00931        sapi_shutdown();
00932 #endif
00933 
00934 #ifdef ZTS
00935        tsrm_shutdown();
00936 #endif
00937 }
00938 /* }}} */
00939 
00940 #if MODULE_MAGIC_NUMBER >= 19970728
00941 /* {{{ php_child_exit_handler
00942  */
00943 static void php_child_exit_handler(server_rec *s, pool *p)
00944 {
00945 /*     apache_php_initialized = 0; */
00946        apache_sapi_module.shutdown(&apache_sapi_module);
00947 
00948 #ifdef ZTS
00949        tsrm_shutdown();
00950 #endif
00951 }
00952 /* }}} */
00953 #endif
00954 
00955 /* {{{ void php_init_handler(server_rec *s, pool *p)
00956  */
00957 static void php_init_handler(server_rec *s, pool *p)
00958 {
00959        register_cleanup(p, NULL, (void (*)(void *))apache_php_module_shutdown_wrapper, (void (*)(void *))php_module_shutdown_for_exec);
00960        if (!apache_php_initialized) {
00961               apache_php_initialized = 1;
00962 #ifdef ZTS
00963               tsrm_startup(1, 1, 0, NULL);
00964 #endif
00965               sapi_startup(&apache_sapi_module);
00966               php_apache_startup(&apache_sapi_module);
00967        }
00968 #if MODULE_MAGIC_NUMBER >= 19980527
00969        {
00970               TSRMLS_FETCH();
00971               if (PG(expose_php)) {
00972                      ap_add_version_component("PHP/" PHP_VERSION);
00973               }
00974        }
00975 #endif
00976 }
00977 /* }}} */
00978 
00979 /* {{{ handler_rec php_handlers[]
00980  */
00981 handler_rec php_handlers[] =
00982 {
00983        {"application/x-httpd-php", send_parsed_php},
00984        {"application/x-httpd-php-source", send_parsed_php_source},
00985        {"text/html", php_xbithack_handler},
00986        {NULL}
00987 };
00988 /* }}} */
00989 
00990 /* {{{ command_rec php_commands[]
00991  */
00992 command_rec php_commands[] =
00993 {
00994        {"php_value",        php_apache_value_handler, NULL, OR_OPTIONS, TAKE2, "PHP Value Modifier"},
00995        {"php_flag",         php_apache_flag_handler, NULL, OR_OPTIONS, TAKE2, "PHP Flag Modifier"},
00996        {"php_admin_value",  php_apache_admin_value_handler, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, "PHP Value Modifier (Admin)"},
00997        {"php_admin_flag",   php_apache_admin_flag_handler, NULL, ACCESS_CONF|RSRC_CONF, TAKE2, "PHP Flag Modifier (Admin)"},
00998        {"PHPINIDir",        php_apache_phpini_set, NULL, RSRC_CONF, TAKE1, "Directory containing the php.ini file"},
00999        {NULL}
01000 };
01001 /* }}} */
01002 
01003 /* {{{ odule MODULE_VAR_EXPORT php5_module
01004  */
01005 module MODULE_VAR_EXPORT php5_module =
01006 {
01007        STANDARD_MODULE_STUFF,
01008        php_init_handler,                  /* initializer */
01009        php_create_dir,                           /* per-directory config creator */
01010        php_merge_dir,                            /* dir merger */
01011        NULL,                                     /* per-server config creator */
01012        NULL,                                     /* merge server config */
01013        php_commands,                      /* command table */
01014        php_handlers,                      /* handlers */
01015        NULL,                                     /* filename translation */
01016        NULL,                                     /* check_user_id */
01017        NULL,                                     /* check auth */
01018        NULL,                                     /* check access */
01019        NULL,                                     /* type_checker */
01020        NULL,                                     /* fixups */
01021        NULL                                      /* logger */
01022 #if MODULE_MAGIC_NUMBER >= 19970103
01023        , NULL                                    /* header parser */
01024 #endif
01025 #if MODULE_MAGIC_NUMBER >= 19970719
01026        , NULL                                    /* child_init */
01027 #endif
01028 #if MODULE_MAGIC_NUMBER >= 19970728
01029        , php_child_exit_handler           /* child_exit */
01030 #endif
01031 #if MODULE_MAGIC_NUMBER >= 19970902
01032        , NULL                                    /* post read-request */
01033 #endif
01034 };
01035 /* }}} */
01036 
01037 /*
01038  * Local variables:
01039  * tab-width: 4
01040  * c-basic-offset: 4
01041  * End:
01042  * vim600: sw=4 ts=4 fdm=marker
01043  * vim<600: sw=4 ts=4
01044  */