이 기사에서는 PHP8의 기본 커널 소스 코드에 대한 심층 분석을 제공하고 SAPI에 대해 알아봅니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.
추천 관련 기사: "PHP8 기반 커널 소스 코드 분석 - 배열(1)"
Docker 아래에 다음 환경 구축
[root@a951700e857d cui-php]# php -v PHP 8.0.2 (cli) (built: Mar 2 2021 02:40:03) ( NTS ) Copyright (c) The PHP Group Zend Engine v4.0.2, Copyright (c) Zend Technologies [root@a951700e857d cui-php]#
Brother Bird 사진 소개
에서 -Zend SAPI(Zend SAPI Internals)에 대한 심층적인 이해
https://link.zhihu.com/?target=https%3A//www.laruence.com/2008/08/12/180.html
SAPI(서버 애플리케이션 프로그래밍 인터페이스, 서버 애플리케이션 프로그래밍 인터페이스)는 PHP 외부 환경의 에이전트와 동일합니다. PHP는 터미널에 적용할 수도 있고 웹 서버에 적용할 수도 있습니다. 터미널에 적용하는 SAPI를 CLI SAPI라고 하고, 웹 서버에 적용하는 SAPI를 CGI SAPI라고 합니다.
이전과 다음을 연결하는 중간 레이어나 글루와 같습니다. sapi의 핵심 정의와 매크로 파일은 Structure_sapi_module_struct
//* sapi_module_struct cgi_sapi_module 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 };
struct _sapi_module_struct { char *name; char *pretty_name; int (*startup)(struct _sapi_module_struct *sapi_module); int (*shutdown)(struct _sapi_module_struct *sapi_module); int (*activate)(void); int (*deactivate)(void); size_t (*ub_write)(const char *str, size_t str_length); void (*flush)(void *server_context); zend_stat_t *(*get_stat)(void); char *(*getenv)(const 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); int (*send_headers)(sapi_headers_struct *sapi_headers); void (*send_header)(sapi_header_struct *sapi_header, void *server_context); size_t (*read_post)(char *buffer, size_t count_bytes); char *(*read_cookies)(void); void (*register_server_variables)(zval *track_vars_array); void (*log_message)(const char *message, int syslog_type_int); double (*get_request_time)(void); void (*terminate_process)(void); char *php_ini_path_override; void (*default_post_reader)(void); void (*treat_data)(int arg, char *str, zval *destArray); char *executable_location; int php_ini_ignore; int php_ini_ignore_cwd; /* don't look for php.ini in the current directory */ int (*get_fd)(int *fd); int (*force_http_10)(void); int (*get_target_uid)(uid_t *); int (*get_target_gid)(gid_t *); unsigned int (*input_filter)(int arg, const char *var, char **val, size_t val_len, size_t *new_val_len); void (*ini_defaults)(HashTable *configuration_hash); int phpinfo_as_text; char *ini_entries; const zend_function_entry *additional_functions; unsigned int (*input_filter_init)(void); };
struct _sapi_module_struct {
char *name; // 名字,如cli、 fpm-fcgi等
char *pretty_name; // 更易理解的名字,比如fpm-fcgi对应的为FPM/FastCGI
int (*startup)(struct _sapi_module_struct *sapi_module);
//模块启动时调用的函数
int (*shutdown)(struct _sapi_module_struct *sapi_module);
//模块结束时调用的函数
int (*activate)(void); // 处理request时,激活需要调用的函数指针
int (*deactivate)(void); // 处理完request时,使要调用的函数指针无效
size_t (*ub_write)(const char *str, size_t str_length);
// 这个函数指针用于输出数据
void (*flush)(void *server_context); // 刷新缓存的函数指针
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); // 调用exit退出时的函数指针
char *php_ini_path_override; // PHP的ini文件被复写的地址
void (*default_post_reader)(void); //负责解析POST数据的函数指针
void (*treat_data)(int arg, char *str, zval *destArray);
// 对数据进行处理的函数指针
char *executable_location; // 执行的地理位置
int php_ini_ignore; // 是否不使用任何ini配置文件
int php_ini_ignore_cwd; // 忽略当前路径的php.ini
int (*get_fd)(int *fd); // 获取执行文件的fd的函数指针
int (*force_http_10)(void); // 强制使用http 1.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配置的函数指针,把ini配置信息存在HashTable中
int phpinfo_as_text; // 是否输出phpinfo信息
char *ini_entries; // 执行时附带的ini配置,可以使用php -d设置
const zend_function_entry *additional_functions;
// 每个SAPI模块特有的一些函数注册,比如cli的cli_get_process_title
unsigned int (*input_filter_init)(void);
};
cgi_main.c를 살펴보면 전체 CGI 코드가 총 900줄이 넘습니다.
일부 코드를 접어보세요. ZTS 관련(스레드 안전 등)
zend_signal_startup 신호 처리 방법(Linux 신호에 대해서는 나중에 설명하겠습니다. 피트가 너무 큽니다.)
sapi_startup(&cgi_sapi_module)을 호출하고 초기화 작업을 수행합니다. sapi_model
typedef struct _sapi_globals_struct { void *server_context; sapi_request_info request_info; sapi_headers_struct sapi_headers; int64_t read_post_bytes; unsigned char post_read; unsigned char headers_sent; zend_stat_t global_stat; char *default_mimetype; char *default_charset; HashTable *rfc1867_uploaded_files; zend_long post_max_size; int options; zend_bool sapi_started; double global_request_time; HashTable known_post_content_types; zval callback_func; zend_fcall_info_cache fci_cache; } sapi_globals_struct;
...
sapi_startup(&cgi_sapi_module);
fastcgi = fcgi_is_fastcgi();
cgi_sapi_module.php_ini_path_override = NULL;
SAPI_API void sapi_startup(sapi_module_struct *sf) { sf->ini_entries = NULL // ini_entries设置null sapi_module = *sf; // 把传进来的结构体赋值给sapi_module // 上面有关于sap_module的 定义 sapi_module_struct sapi_module; //这里你可以理解为 初始化了sapi_module_struct #ifdef ZTS ts_allocate_fast_id(&sapi_globals_id, &sapi_globals_offset, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor); # ifdef PHP_WIN32 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); # endif #else sapi_globals_ctor(&sapi_globals); #endif #ifdef PHP_WIN32 tsrm_win32_startup(); #endif reentrancy_startup(); }
memset은 기본입니다. C언어로 메모리 초기화 방법
static void sapi_globals_ctor(sapi_globals_struct *sapi_globals) { memset(sapi_globals, 0, sizeof(*sapi_globals)); zend_hash_init(&sapi_globals->known_post_content_types, 8, NULL, _type_dtor, 1); php_setup_sapi_content_types(); }
下面是 memset() 函数的声明。 void *memset(void *str, int c, size_t n) 参数 str -- 指向要填充的内存块。 c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。 n -- 要被设置为该值的字符数。 返回值 该值返回一个指向存储区 str 的指针。
/* {{{ php_startup_sapi_content_types */ int php_startup_sapi_content_types(void) { sapi_register_default_post_reader(php_default_post_reader); sapi_register_treat_data(php_default_treat_data); sapi_register_input_filter(php_default_input_filter, NULL); return SUCCESS; }
sapi_startup(&cgi_sapi_module); fastcgi = fcgi_is_fastcgi(); cgi_sapi_module.php_ini_path_override = NULL;
그래서 fcgi_init() 함수
int fcgi_is_fastcgi(void) { if (!is_initialized) { return fcgi_init(); } else { return is_fastcgi; } }
로 가서 fgi 프로토콜 관련 내용을 초기화했습니다
글이 너무 길어서 작성하지 못했습니다. 내일 보충하겠습니다. 먼저 gdb로 cli 모드를 분석하겠습니다
이 기사는 원저자 PHP Cui Xuefeng의 승인을 받아 PHP 중국어 웹사이트(원본 주소: https://zhuanlan.zhihu)에 게시되었습니다. .com/p/356037371
추천 학습: "PHP 비디오 튜토리얼
"위 내용은 PHP8의 기본 커널 소스 코드인 SAPI에 대한 심층 분석(1)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!