[PHP内核]PHP内核学习------SAPI学习

Posted Y4tacker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[PHP内核]PHP内核学习------SAPI学习相关的知识,希望对你有一定的参考价值。

写在前面

新开一个坑,虽然未来php用的不多,但是学起来还是有点意思

SAPI学习

什么是SAPI

从php7内核剖析当中提到

PHP本身可以理解为是一个库函数,提供语言的编译与执行服务,它有标准的输入、输出,
而SAPI是PHP的接入层,它接收用户的请求,然后调用PHP内核提供的一些接口完成PHP脚
本的执行


从图中可以看出,各种应用都是通过对应的SAPI与php进行交互的,SAPI相当于一个接口,使得php的核心实现不用关心各个应用交互的细节。虽然通过Web服务器和命令行程序执行脚本看起来很不一样,实际上它们的工作流程是一样的。
而PHP中常用的SAPI有cli、php-fpm,cli是命令行下执行PHP脚本的实现

sapi_module_struct结构

简单注释

这个结构是sapi中最重要的数据结构。它的定义在main/SAPI.h中

struct _sapi_module_struct {  // SAPI模块结构
    char *name; // 应用层名称,比如cli,cgi等
    char *pretty_name; // 应用层更易读的名字,比如cli对应的就是Command Line Interface

    int (*startup)(struct _sapi_module_struct *sapi_module); // 当一个应用要调用php的时候,这个模块启动的时候会调用的函数
    int (*shutdown)(struct _sapi_module_struct *sapi_module); // 当一个应用要调用php的时候,这个模块结束的时候会调用的函数

    int (*activate)(void); // 在处理每个request的时候,激活需要调用的函数
    int (*deactivate)(void); // 在处理完每个request的时候,收尾时候要调用的函数

    size_t (*ub_write)(const char *str, size_t str_length); // 这个函数告诉php如何输出数据
    void (*flush)(void *server_context); // 提供给php的刷新缓存的函数指针
    zend_stat_t *(*get_stat)(void); // 用来判断要执行文件的权限,来判断是否有执行权限
    char *(*getenv)(char *name, size_t name_len); // 获取环境变量的方法

    void (*sapi_error)(int type, const char *error_msg, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); // 错误处理方法

    int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers); // 这个函数会在我们调用header()的时候被调用
    int (*send_headers)(sapi_headers_struct *sapi_headers); // 发送所有的header
    void (*send_header)(sapi_header_struct *sapi_header, void *server_context); // 单独发送某一个header

    size_t (*read_post)(char *buffer, size_t count_bytes); // 如何获取HTTP POST中的数据
    char *(*read_cookies)(void);  // 如何获取cookie中的数据

    void (*register_server_variables)(zval *track_vars_array); // 这个函数可以给$_SERVER中获取变量
    void (*log_message)(char *message, int syslog_type_int); // 输出错误信息函数
    double (*get_request_time)(void); // 获取请求时间的函数
    void (*terminate_process)(void);  // TODO: 调用exit的时候调用的方法

    char *php_ini_path_override;  // PHP的ini文件被复写了所复写的地址

    void (*default_post_reader)(void); // 这里和前面的read_post有个差别,read_post负责如何获取POST数据,而这里的函数负责如何解析POST数据
    void (*treat_data)(int arg, char *str, zval *destArray); // 对数据进行处理,比如进行安全过滤等。 default_post_reader/tread_data/input_filter是三个能对输入进行过滤和处理的函数
    char *executable_location; // 执行的地理位置

    int php_ini_ignore; // 是否不使用任何ini配置文件,比如php -n 就将这个位置设置为1
    int php_ini_ignore_cwd; // 不在当前路径寻找php.ini

    int (*get_fd)(int *fd); // 获取执行文件的fd

    int (*force_http_10)(void); // 强制使用http1.0

    int (*get_target_uid)(uid_t *); // 获取执行程序的uid
    int (*get_target_gid)(gid_t *); // 获取执行程序的gid

    unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len); // 对输入进行过滤。比如将输入参数填充到自动全局变量$_GET, $_POST, $_COOKIE中

    void (*ini_defaults)(HashTable *configuration_hash); // 默认的ini配置
    int phpinfo_as_text; // 是否打印phpinfo信息

    char *ini_entries; // 有没有附带的ini配置,比如使用php -d date.timezone=America/Adak,可以在命令行中设置时区
    const zend_function_entry *additional_functions; // 每个SAPI模块特有的一些函数注册,比如cli的cli_get_process_title
    unsigned int (*input_filter_init)(void); // TODO:
};

接下来我们看看不同模式下定义

cgi模式

cgi模式下,_sapi_module_struct的实例定义在cgi_main.c中。

static sapi_module_struct cgi_sapi_module = {
    "cgi-fcgi",                     /* name */
    "CGI/FastCGI",                  /* pretty name */
    php_cgi_startup,                /* startup */
    php_module_shutdown_wrapper,    /* shutdown */
    sapi_cgi_activate,              /* activate */
    sapi_cgi_deactivate,            /* deactivate */
    sapi_cgi_ub_write,              /* unbuffered write */
    sapi_cgi_flush,                 /* flush */
    NULL,                           /* get uid */
    sapi_cgi_getenv,                /* getenv */
    php_error,                      /* error handler */
    NULL,                           /* header handler */
    sapi_cgi_send_headers,          /* send headers handler */
    NULL,                           /* send header handler */
    sapi_cgi_read_post,             /* read POST data */
    sapi_cgi_read_cookies,          /* read Cookies */
    sapi_cgi_register_variables,    /* register server variables */
    sapi_cgi_log_message,           /* Log message */
    NULL,                           /* Get request time */
    NULL,                           /* Child terminate */
    STANDARD_SAPI_MODULE_PROPERTIES
};

cli 模式

在php_cli.c

static sapi_module_struct cli_sapi_module = {
    "cli",                          /* name */
    "Command Line Interface",       /* pretty name */
    php_cli_startup,                /* startup */
    php_module_shutdown_wrapper,    /* shutdown */
    NULL,                           /* activate */
    sapi_cli_deactivate,            /* deactivate */
    sapi_cli_ub_write,              /* unbuffered write */
    sapi_cli_flush,                 /* flush */
    NULL,                           /* get uid */
    NULL,                           /* getenv */
    php_error,                      /* error handler */
    sapi_cli_header_handler,        /* header handler */
    sapi_cli_send_headers,          /* send headers handler */
    sapi_cli_send_header,           /* send header handler */
    NULL,                           /* read POST data */
    sapi_cli_read_cookies,          /* read Cookies */
    sapi_cli_register_variables,    /* register server variables */
    sapi_cli_log_message,           /* Log message */
    NULL,                           /* Get request time */
    NULL,                           /* Child terminate */
    STANDARD_SAPI_MODULE_PROPERTIES
};

fpm

static sapi_module_struct cgi_sapi_module = {
	"fpm-fcgi",						/* name */
	"FPM/FastCGI",					/* pretty name */

	php_cgi_startup,				/* startup */
	php_module_shutdown_wrapper,	/* shutdown */

	sapi_cgi_activate,				/* activate */
	sapi_cgi_deactivate,			/* deactivate */

	sapi_cgibin_ub_write,			/* unbuffered write */
	sapi_cgibin_flush,				/* flush */
	NULL,							/* get uid */
	sapi_cgibin_getenv,				/* getenv */

	php_error,						/* error handler */

	NULL,							/* header handler */
	sapi_cgi_send_headers,			/* send headers handler */
	NULL,							/* send header handler */

	sapi_cgi_read_post,				/* read POST data */
	sapi_cgi_read_cookies,			/* read Cookies */

	sapi_cgi_register_variables,	/* register server variables */
	sapi_cgi_log_message,			/* Log message */
	NULL,							/* Get request time */
	NULL,							/* Child terminate */

	STANDARD_SAPI_MODULE_PROPERTIES
};

简单总结

可以看见上面不同模式部分定义也不同,比如是否能获取cookie等,简单了解下即可

以上是关于[PHP内核]PHP内核学习------SAPI学习的主要内容,如果未能解决你的问题,请参考以下文章

[PHP内核]PHP内核学习------sapi_module_struct结构体解析(以cli为例)

[PHP内核]PHP内核学习------sapi_module_struct结构体解析(以cli为例)

[PHP内核]PHP内核学习------sapi_module_struct结构体解析(以cli为例)

PHP内核学习SAPI

跟厂长学PHP7内核:系统分析生命周期

跟厂长学PHP7内核:一步步分析生命周期之模块初始化阶段