您好,欢迎访问一九零五行业门户网

PHP内核-Apache2的SAPI_PHP教程

我们知道定义sapi之前,首先要定义sapi_module_struct这个结构,相看源码:/soft/php-5.2.9/sapi/apache2handler/sapi_apache2.c,可以看到定义该结构,我直接复制过来:
[cpp] 
static sapi_module_struct apache2_sapi_module = { 
        apache2handler, 
        apache 2.0 handler,
php_apache2_startup,                            /* startup */ 
        php_module_shutdown_wrapper,                    /* shutdown */
null,                                           /* activate */ 
        null,                                           /* deactivate */
php_apache_sapi_ub_write,                       /* unbuffered write */ 
        php_apache_sapi_flush,                          /* flush */ 
        php_apache_sapi_get_stat,                       /* get uid */ 
        php_apache_sapi_getenv,                         /* getenv */
php_error,                                      /* error handler */
php_apache_sapi_header_handler,                 /* header handler */ 
        php_apache_sapi_send_headers,                   /* send headers handler */ 
        null,                                           /* send header handler */
php_apache_sapi_read_post,                      /* read post data */ 
        php_apache_sapi_read_cookies,                   /* read cookies */
php_apache_sapi_register_variables, 
        php_apache_sapi_log_message,                    /* log message */ 
        php_apache_sapi_get_request_time,               /* request time */
standard_sapi_module_properties 
}; 
1,php_apache2_startup:当通过apache调用php时,这个函数会被调用。该函数定义如下,主要是对php进行初始化。
[cpp]
static int php_apache2_startup(sapi_module_struct *sapi_module) 

        if (php_module_startup(sapi_module, &php_apache_module, 1)==failure) { 
                return failure; 
        } 
        return success; 

2,php_module_shutdown_wrapper :php的关闭函数。
3,php会在每个request的时候,处理一些初始化,资源分配的事务。这部分就是activate字段要定义的。
4,与activate的函数,就是deactiveate,它会提供一个handler, 用来处理收尾工作。
5,php_apache_sapi_ub_write:提供一个向response数据写的接口。
[cpp]
static int 
php_apache_sapi_ub_write(const char *str, uint str_length tsrmls_dc) 

        request_rec *r; 
        php_struct *ctx;
ctx = sg(server_context); 
        r = ctx->r;
if (ap_rwrite(str, str_length, r)                 php_handle_aborted_connection(); 
        }
return str_length; /* we always consume all the data passed to us. */ 
}
6,php_apache_sapi_flush:提供给zend刷新缓存的句柄。
[cpp]
static void 
php_apache_sapi_flush(void *server_context) 

        php_struct *ctx; 
        request_rec *r; 
        tsrmls_fetch();
ctx = server_context;
/* if we haven't registered a server_context yet,
         * then don't bother flushing. */ 
        if (!server_context) { 
                return; 
        }
r = ctx->r;
sapi_send_headers(tsrmls_c);
r->status = sg(sapi_headers).http_response_code; 
        sg(headers_sent) = 1;
if (ap_rflush(r) connection->aborted) { 
                php_handle_aborted_connection(); 
        } 

7,php_apache_sapi_get_stat:这部分用来让zend可以验证一个要执行脚本文件的state,从而判断文件是否据有执行权限等等。
[cpp]
static struct stat* 
php_apache_sapi_get_stat(tsrmls_d) 

        php_struct *ctx = sg(server_context);
ctx->finfo.st_uid = ctx->r->finfo.user; 
        ctx->finfo.st_gid = ctx->r->finfo.group; 
        ctx->finfo.st_dev = ctx->r->finfo.device; 
        ctx->finfo.st_ino = ctx->r->finfo.inode; 
#if defined(netware) && defined(clib_stat_patch) 
        ctx->finfo.st_atime.tv_sec = apr_time_sec(ctx->r->finfo.atime); 
        ctx->finfo.st_mtime.tv_sec = apr_time_sec(ctx->r->finfo.mtime); 
        ctx->finfo.st_ctime.tv_sec = apr_time_sec(ctx->r->finfo.ctime); 
#else 
        ctx->finfo.st_atime = apr_time_sec(ctx->r->finfo.atime); 
        ctx->finfo.st_mtime = apr_time_sec(ctx->r->finfo.mtime); 
        ctx->finfo.st_ctime = apr_time_sec(ctx->r->finfo.ctime); 
#endif
ctx->finfo.st_size = ctx->r->finfo.size; 
        ctx->finfo.st_nlink = ctx->r->finfo.nlink;
return &ctx->finfo; 

8,php_apache_sapi_getenv:为zend提供了一个根据name来查找环境变量的接口,当我们在脚本中调用getenv的时候,就会间接的调用这个句柄。
[cpp] 
static char * 
php_apache_sapi_getenv(char *name, size_t name_len tsrmls_dc) 

        php_struct *ctx = sg(server_context); 
        const char *env_var;
env_var = apr_table_get(ctx->r->subprocess_env, name);
return (char *) env_var; 

9,php_error:错误处理函数,直接调用php错误处理函数。
10,php_apache_sapi_header_handler:在调用php的header()函数时,会调用这个函数。
[cpp]
static int 
php_apache_sapi_header_handler(sapi_header_struct *sapi_header,sapi_headers_struct *sapi_headers tsrmls_dc) 

        php_struct *ctx; 
        char *val, *ptr;
ctx = sg(server_context);
val = strchr(sapi_header->header, ':');
if (!val) { 
                sapi_free_header(sapi_header); 
                return 0; 
        } 
        ptr = val;
*val = '\0';
do { 
                val++; 
        } while (*val == ' '); 
        if (!strcasecmp(sapi_header->header, content-type)) { 
                if (ctx->content_type) { 
                        efree(ctx->content_type); 
                } 
                ctx->content_type = estrdup(val); 
        } else if (sapi_header->replace) { 
                apr_table_set(ctx->r->headers_out, sapi_header->header, val); 
        } else { 
                apr_table_add(ctx->r->headers_out, sapi_header->header, val); 
        } 
        *ptr = ':';
return sapi_header_add; 

11,php_apache_sapi_send_headers:当要真正发送header的时候,这个函数会被调用。
[cpp] 
static int 
php_apache_sapi_send_headers(sapi_headers_struct *sapi_headers tsrmls_dc) 

        php_struct *ctx = sg(server_context); 
        const char *sline = sg(sapi_headers).http_status_line;
ctx->r->status = sg(sapi_headers).http_response_code;
/* httpd requires that r->status_line is set to the first digit of
         * the status-code: */ 
        if (sline && strlen(sline) > 12 && strncmp(sline, http/1., 7) == 0 && sline[8] == ' ') { 
                ctx->r->status_line = apr_pstrdup(ctx->r->pool, sline + 9); 
                ctx->r->proto_num = 1000 + (sline[7]-'0'); 
                if ((sline[7]-'0') == 0) { 
                        apr_table_set(ctx->r->subprocess_env, force-response-1.0, true); 
                } 
        }
/*      call ap_set_content_type only once, else each time we call it,
                configured output filters for that content type will be added */ 
        if (!ctx->content_type) { 
                ctx->content_type = sapi_get_default_content_type(tsrmls_c); 
        } 
        ap_set_content_type(ctx->r, apr_pstrdup(ctx->r->pool, ctx->content_type)); 
        efree(ctx->content_type); 
        ctx->content_type = null;
return sapi_header_sent_successfully; 

12,在php_apache_sapi_send_headers指针下面有一个域,用来指明发送每一个单独的header时调用。
13,php_apache_sapi_read_post:表示如何读取post数据。
[cpp]
static int  
php_apache_sapi_read_post(char *buf, uint count_bytes tsrmls_dc) 

        apr_size_t len, tlen=0; 
        php_struct *ctx = sg(server_context); 
        request_rec *r; 
        apr_bucket_brigade *brigade;
r = ctx->r; 
        brigade = ctx->brigade; 
        len = count_bytes;
/*
         * this loop is needed because ap_get_brigade() can return us partial data
         * which would cause premature termination of request read. therefor we
         * need to make sure that if data is available we fill the buffer completely.
         */
while (ap_get_brigade(r->input_filters, brigade, ap_mode_readbytes, apr_block_read, len) == apr_success) { 
                apr_brigade_flatten(brigade, buf, &len); 
                apr_brigade_cleanup(brigade); 
                tlen += len; 
                if (tlen == count_bytes || !len) { 
                        break; 
                } 
                buf += len; 
                len = count_bytes - tlen; 
        }
return tlen; 
}
14,php_apache_sapi_read_cookie:如何读取cookie。
[cpp]
static char * 
php_apache_sapi_read_cookies(tsrmls_d) 

        php_struct *ctx = sg(server_context); 
        const char *http_cookie;
http_cookie = apr_table_get(ctx->r->headers_in, cookie);
/* the sapi interface should use 'const char *' */ 
        return (char *) http_cookie; 

15,php_apache_sapi_register_variables:提供接口,用于给$_server[]数组提供变量。
[cpp]
static void 
php_apache_sapi_register_variables(zval *track_vars_array tsrmls_dc) 

        php_struct *ctx = sg(server_context); 
        const apr_array_header_t *arr = apr_table_elts(ctx->r->subprocess_env); 
        char *key, *val; 
        int new_val_len;
apr_array_foreach_open(arr, key, val) 
                if (!val) { 
                        val = ; 
                } 
                if (sapi_module.input_filter(parse_server, key, &val, strlen(val), &new_val_len tsrmls_cc)) { 
                        php_register_variable_safe(key, val, new_val_len, track_vars_array tsrmls_cc); 
                } 
        apr_array_foreach_close()
if (sapi_module.input_filter(parse_server, php_self, &ctx->r->uri, strlen(ctx->r->uri), &new_val_len tsrmls_cc)) { 
                php_register_variable_safe(php_self, ctx->r->uri, new_val_len, track_vars_array tsrmls_cc); 
        } 

16,php_apache_sapi_log_message:输出错误信息。
[cpp]
static void php_apache_sapi_log_message(char *msg) 

        php_struct *ctx; 
        tsrmls_fetch();
ctx = sg(server_context);
if (ctx == null) { /* we haven't initialized our ctx yet, oh well */ 
                ap_log_error(aplog_mark, aplog_err | aplog_startup, 0, null, %s, msg); 
        } else { 
                ap_log_rerror(aplog_mark, aplog_err, 0, ctx->r, %s, msg); 
        } 
}
17,php_apache_sapi_get_request_time:获取请求时间。
[cpp] 
static time_t php_apache_sapi_get_request_time(tsrmls_d) { 
        php_struct *ctx = sg(server_context); 
        return apr_time_sec(ctx->r->request_time); 

这就完成了apache的sapi定义。之后,就是当用户用url请求apache服务,这些函数指针就会在适当的时候,发挥作用了(被调用)。
http://www.bkjia.com/phpjc/477971.htmlwww.bkjia.comtruehttp://www.bkjia.com/phpjc/477971.htmltecharticle我们知道定义sapi之前,首先要定义sapi_module_struct这个结构,相看源码:/soft/php-5.2.9/sapi/apache2handler/sapi_apache2.c,可以看到定义该结构,我直...
其它类似信息

推荐信息