概述

😐 本来是看看 WordPress。没想到越看需要看的就越多,遂记录一下。虽然现在 AI 已经很好用了,但是该记还是得记,这种比较杂的知识点,AI 也不能一次性涉及到。本文涉及 PHP 从源码到逆向、关键函数、关键变量、zend 等相关概念。

本文部分内容由 AI 生成,经人工修订。

文章目录无先后顺序,根据学习进度随手记录

[toc]

相关参考

php 源码

这一部分涉及源码的下载、编译部分。

下载

  1. 可以从 PHP 的 Github 页面下载历史版本

    php/php-src: The PHP Interpreter

  2. 也可以在 Windows.php.NET 页面下载

    windows.php.net - /downloads/releases/archives/

编译

编译部分开源官方已经提供了脚本文件,直接运行编译即可,流程相对比较简单。

编译部分可以参考文章:PHP 源码编译

相关变量

CG 和 EG

这一部分参考了部分网上的文章,主要是理解这两个全局宏,对了解 zend 框架来说是关键的一步。

**CG **

CG 的含义是 compiler_globals,Zend 编译器相关的全局变量,并且,在 PHP 内核中,会通过 CG 宏来获取函数的句柄结构体。compiler_globals.function_table 里面存 储了所有我们可以在 PHP 页面里面调用的函数,包括 Zend 内建函数、PHP 标准库函数、模块导出的函数以及用户使用 PHP 代码定义的函数。

定义如下所示:

// zend_globals_macros.h 
#define CG(v) (compiler_globals.v)

直接访问_zend_compiler_globals 结构体实例,该结构体在 zend_compile.c 中定义为全局变量:

ZEND_API zend_compiler_globals compiler_globals;

zend_compiler_globals 对应的结构体如下所示,其中 HashTable 就是接下来要查找对应函数需要用到的函数表:

struct _zend_compiler_globals {
	zend_stack loop_var_stack;
 
	zend_class_entry *active_class_entry;
 
	zend_string *compiled_filename;
 
	int zend_lineno;
 
	zend_op_array *active_op_array;
 
	HashTable *function_table;	/* function symbol table */
	HashTable *class_table;		/* class table */
 
	HashTable filenames_table;
 
	HashTable *auto_globals;
 
	zend_bool parse_error;
	zend_bool in_compilation;
	zend_bool short_tags;
 
	zend_bool unclean_shutdown;
 
	zend_bool ini_parser_unbuffered_errors;
 
	zend_llist open_files;
 
	struct _zend_ini_parser_param *ini_parser_param;
 
	uint32_t start_lineno;
	zend_bool increment_lineno;
 
	zend_string *doc_comment;
	uint32_t extra_fn_flags;
 
	uint32_t compiler_options; /* set of ZEND_COMPILE_* constants */
 
	zend_oparray_context context;
	zend_file_context file_context;
 
	zend_arena *arena;
 
	HashTable interned_strings;
 
	const zend_encoding **script_encoding_list;
	size_t script_encoding_list_size;
	zend_bool multibyte;
	zend_bool detect_unicode;
	zend_bool encoding_declared;
 
	zend_ast *ast;
	zend_arena *ast_arena;
 
	zend_stack delayed_oplines_stack;
 
#ifdef ZTS
	zval **static_members_table;
	int last_static_member;
#endif
};

最核心的一点就是,Zend 引擎会通过 compiler_globals(CG 宏)访问编译器全局符号表,如下所示:

// 伪代码示例
zend_function *func = zend_hash_str_find_ptr(
    &CG(function_table),  // 编译器函数符号表
    "exec",               // 目标函数名 
    strlen("exec")        // 函数名长度 
);

返回的 zend_function 结构体包含函数指针、参数信息等关键数据。

compiler_globals 的核心作用

  • 存储编译阶段的全局状态,包括:
    • function_table:所有已定义函数的哈希表
    • class_table:类定义表
    • auto_globals:自动全局变量
  • 通过 CG()宏快速访问(如 CG(function_table))

EG

EG 的含义是 executor_globals。Zend 执行器相关的全局变量。Zend 引擎在执行 Opcode 的时候,需要记录一些执行过程中的状态。如,当前执行的类作用域,当前已经加载了那些文件等。

另外的,EG 和 CG 有一些数据是共用的。如,function_table (存储方法信息) , class_table (存储类信息) 。

相关代码在 Zend/zend_execute_API.cinit_executor 方法中发现如下代码:

 
void init_executor(void) /* {{{ */
{
	zend_init_fpu();
 
	ZVAL_NULL(&EG(uninitialized_zval));
	ZVAL_ERROR(&EG(error_zval));
/* destroys stack frame, therefore makes core dumps worthless */
#if 0&&ZEND_DEBUG
	original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
#endif
 
	EG(symtable_cache_ptr) = EG(symtable_cache) - 1;
	EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE - 1;
	EG(no_extensions) = 0;
 
	EG(function_table) = CG(function_table);
	EG(class_table) = CG(class_table);
	
    ...
 
	EG(active) = 1;
}

sapi

全局结构体

sapi 中一个很重要的结构体,也是全局变量

 
/* {{{ 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
};