diff --git a/001.md b/001.md index 86d1baa..34154cd 100644 --- a/001.md +++ b/001.md @@ -4,7 +4,8 @@ git clone https://github.com/php/php-src.git cd php-src - ./configure --prefix=/opt/php-debug --enable-debug --enable-cli --without-pear --enable-embed + CFLAGS=-ggdb3 + ./configure --prefix=/opt/php-debug --enable-debug --enable-cli --without-pear --enable-embed --enable-phpdbg make make install mkdir /opt/php-debug/conf/ @@ -110,4 +111,26 @@ warning: Temporarily disabling breakpoints for unloaded shared library "/opt/php-debug/lib/php/extensions/debug-non-zts-20121212/hello2.so" [Inferior 1 (process 3162) exited normally] - \ No newline at end of file + (gdb) define phpbt + set $ed=execute_data + while $ed + print ((zend_execute_data *)$ed)->function_state.function->common.function_name + set $ed = ((zend_execute_data *)$ed)->prev_execute_data + end + end + (gdb) define hashkeys + set $p = (HashTable*)$arg0->pListHead + while $p + output (Bucket*)$p + echo \t + x/s (char*)(((Bucket*)$p)->arKey) + set $p = ((Bucket*)$p)->pListNext + end + end + (gdb) define bucketdata + print **(zval**)(((struct bucket *) $arg0)->pData) + end + + (gdb) hashkeys executor_globals.included_files + (Bucket *) 0x7ffff7fe1be0 0x7ffff7fe1c28: "/temp/echo.php" + diff --git a/004.md b/004.md new file mode 100644 index 0000000..fe80479 --- /dev/null +++ b/004.md @@ -0,0 +1,170 @@ +# ZendMM + +1, php内存管理内置函数 + + void *emalloc(size_t size) 分配 size 字节的内存。 + void *ecalloc(size_t nmemb, size_t size) 给 nmemb 元素分配 size 字节的缓冲区并初始化为零。 + void *erealloc(void *ptr, size_t size) 修改使用 emalloc 分配的缓冲区 ptr 的大小为 size 字节。 + void efree(void *ptr) 释放 ptr 指向的缓冲区。缓冲区必须是由 emalloc 分配的。 + void *safe_emalloc(size_t nmemb, size_t size, size_t offset) + char *estrdup(const char *s) 分配一个可存放 NULL 结尾的字符串 s 的缓冲区,并将 s复制到缓冲区内。 + char *estrndup(const char *s, unsigned int length) 类似于 estrdup,但 NULL 结尾的字符串长度是已知的。 + +2,由emalloc分配的内存都是在zend_mm_heap上 + + //zend_mm_mem_handlers + typedef struct _zend_mm_mem_handlers { + const char *name; + zend_mm_storage* (*init)(void *params); + void (*dtor)(zend_mm_storage *storage); + void (*compact)(zend_mm_storage *storage); + zend_mm_segment* (*_alloc)(zend_mm_storage *storage, size_t size); + zend_mm_segment* (*_realloc)(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size); + void (*_free)(zend_mm_storage *storage, zend_mm_segment *ptr); + } zend_mm_mem_handlers; + + //zend_mm_segment + typedef struct _zend_mm_segment { + size_t size; + struct _zend_mm_segment *next_segment; + } zend_mm_segment; + + //zend_mm_storage结构 + struct _zend_mm_storage { + const zend_mm_mem_handlers *handlers;//zend_mm_storage方法 (ZEND_MM_MEM_MALLOC_DSC) + void *data; + }; + + //zend_mm_heap结构 + struct _zend_mm_heap { + int use_zend_alloc; + void *(*_malloc)(size_t); + void (*_free)(void*); + void *(*_realloc)(void*, size_t); + size_t free_bitmap; + size_t large_free_bitmap; + size_t block_size; + size_t compact_size; + zend_mm_segment *segments_list; + zend_mm_storage *storage; + size_t real_size; + size_t real_peak; + size_t limit; + size_t size; + size_t peak; + size_t reserve_size; + void *reserve; + int overflow; + int internal; + #if ZEND_MM_CACHE + unsigned int cached; + zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS]; + #endif + zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2]; + zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS]; + zend_mm_free_block *rest_buckets[2]; + int rest_count; + #if ZEND_MM_CACHE_STAT + struct { + int count; + int max_count; + int hit; + int miss; + } cache_stat[ZEND_MM_NUM_BUCKETS+1]; + #endif + }; + + //zend_alloc_globals结构 + typedef struct _zend_alloc_globals { + zend_mm_heap *mm_heap; + } + + //AG宏定义 + # define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v) + + //emalloc函数原型 + ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { + TSRMLS_FETCH(); + + if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) { + return AG(mm_heap)->_malloc(size); + } + return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + } + +3,ZendMM环境变量 + +USE_ZEND_ALLOC 是否使用 ZendMM 进行内存管理。 +ZEND_MM_MEM_TYPE 指定内存分配的方案,默认 malloc +ZEND_MM_COMPACT 指定压缩边界值 + +//默认ZEND_MM_MEM_TYPE初始化 + + # define ZEND_MM_MEM_MALLOC_DSC {"malloc", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_malloc_alloc, zend_mm_mem_malloc_realloc, zend_mm_mem_malloc_free} + + # define ZEND_MM_MEM_WIN32_DSC {"win32", zend_mm_mem_win32_init, zend_mm_mem_win32_dtor, zend_mm_mem_win32_compact, zend_mm_mem_win32_alloc, zend_mm_mem_win32_realloc, zend_mm_mem_win32_free} + + # define ZEND_MM_MEM_MMAP_ZERO_DSC {"mmap_zero", zend_mm_mem_mmap_zero_init, zend_mm_mem_mmap_zero_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_zero_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free} + + # define ZEND_MM_MEM_MMAP_ANON_DSC {"mmap_anon", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_anon_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free} + +4,ZendMM 流程 + + ->SAPI + ->php_module_startup (main.c 2065) + ->zend_startup() //zend引擎启动 + ->start_memory_manager(TSRMLS_C) //开始内存管理 + ->ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor) //初始化AG + + ->alloc_globals_ctor(&alloc_globals) //申请内存 + + //分配内存,读取环境变量USE_ZEND_ALLOC,如果USE_ZEND_ALLOC==0 则禁用 ZendMMApi(emalloc/efree/...) + //初始化mm_heap的代码(USE_ZEND_ALLOC != 0) + alloc_globals->mm_heap = malloc(sizeof(struct _zend_mm_heap)); + memset(alloc_globals->mm_heap, 0, sizeof(struct _zend_mm_heap)); + alloc_globals->mm_heap->use_zend_alloc = 0; + alloc_globals->mm_heap->_malloc = malloc; + alloc_globals->mm_heap->_free = free; + alloc_globals->mm_heap->_realloc = realloc; + + //初始化mm_heap的代码(USE_ZEND_ALLOC != 0), 则启用 ZendMMApi(emalloc/efree/...) + alloc_globals->mm_heap = zend_mm_startup(); + + ->zend_mm_startup() //读取内存分配方案(默认malloc) + ->zend_mm_startup_ex() //实例化zend_mm_heap分配内存 (heap = malloc(sizeof(struct _zend_mm_heap));) + + ->emalloc() //申请内存, + //zend_mm_heap->use_zend_alloc==0 调用 mm_heap->_malloc方法初始化分配内存 + //zend_mm_heap->use_zend_alloc!=0 调用 _zend_mm_alloc_int + ->_zend_mm_alloc_int() + ->ZEND_MM_STORAGE_ALLOC(segment_size) // + -> heap->storage->handlers->_alloc + + //ZEND_MM_MEM_WIN32_DSC + ->zend_mm_mem_win32_alloc() + ->HeapAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, size)//最终把内存分配到了heap->storage->data + + //ZEND_MM_MEM_MALLOC_DSC + ->zend_mm_mem_malloc_alloc() + ->return (zend_mm_segment*)malloc(size) //最终把内存分配到了 heap->segments_list + + //ZEND_MM_MEM_MMAP_ZERO_DSC + ->zend_mm_mem_mmap_zero_alloc() + ->(zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zend_mm_dev_zero_fd, 0) //通过mmap把内存影射到heap->storage + + //ZEND_MM_MEM_MMAP_ANON_DSC + ->zend_mm_mem_mmap_anon_alloc + ->(zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0) + //最终把内存分配到了 heap->segments_list + + ->alloc_globals_dtor() //释放内存 + ->shutdown_memory_manager (main.c 2410) //结束内存管理 + ->zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC) //最终调用释放内存的方法 + +5,总结 + + a) ZEND_MM_MEM_WIN32_DSC|ZEND_MM_MEM_MMAP_ZERO_DSC 内存保存到了 heap->storage + ZEND_MM_MEM_MMAP_ANON_DSC|ZEND_MM_MEM_MALLOC_DSC 内存保存到了 heap->segments_list + + b) \ No newline at end of file diff --git a/02.md b/02.md index 7b0c278..5f6e6f8 100644 --- a/02.md +++ b/02.md @@ -24,7 +24,7 @@ static PHP_FUNCTION(params_add) { long a,b; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &a, &b) == FALSE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &a, &b) == FAILURE) { return; } RETURN_LONG(a+b); @@ -60,7 +60,7 @@ //宏说明 ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) //开始参数块定义,pass_rest_by_reference为1时,强制所有参数为引用类型 ZEND_END_ARG_INFO() //结束参数块定义 - ZEND_ARG_INFO //声明普通参数,可以用来表示PHP中的int, float, double, string等基本数组类型 + ZEND_ARG_INFO //声明普通参数,可以用来表示PHP中的int, float, double, string等基本数据类型 ZEND_ARG_OBJ_INFO //声明对象类型的参数 ZEND_ARG_ARRAY_INFO //声明数组类型的参数 ZEND_ARG_PASS_INFO(pass_by_ref) //pass_by_ref为1时,强制设置后续的参数为引用类型 @@ -173,4 +173,4 @@ - \ No newline at end of file + diff --git a/04.md b/04.md index 37f71bb..93bb07d 100644 --- a/04.md +++ b/04.md @@ -1,131 +1,225 @@ # INI参数设置 -1,创建一个新的扩展 +## 创建一个新的扩展 - ./ext_skel --extname=inis ++ 生成扩展 -2,宏 +``` +./ext_skel --extname=inis +``` - #define ZEND_DECLARE_MODULE_GLOBALS(module_name) ts_rsrc_id module_name##_globals_id; - - #define STD_PHP_INI_ENTRY STD_ZEND_INI_ENTRY - #define STD_ZEND_INI_ENTRY(name, default_value, modifiable, on_modify, property_name, struct_type, struct_ptr) \ - ZEND_INI_ENTRY2(name, default_value, modifiable, on_modify, (void *) XtOffsetOf(struct_type, property_name), (void *) &struct_ptr##_id) - #define ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, arg1, arg2, arg3, displayer) \ ++ config.m4 + +``` +PHP_ARG_ENABLE(inis, whether to enable inis support, +[ --enable-inis Enable inis support]) + +if test "$PHP_INIS" != "no"; then + PHP_NEW_EXTENSION(inis, inis.c, $ext_shared) +fi +``` + ++ php_inis.h + +``` +ZEND_BEGIN_MODULE_GLOBALS(inis) + char *name; + long level; +ZEND_END_MODULE_GLOBALS(inis) + +#ifdef ZTS +#define INIS_G(v) TSRMG(inis_globals_id, zend_inis_globals *, v) +#else +#define INIS_G(v) (inis_globals.v) +#endif +``` + ++ inis.c + +定义全局变量 + +```c +ZEND_DECLARE_MODULE_GLOBALS(inis) +``` + +设置INI参数 + +```c +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("inis.name","sunzy",PHP_INI_ALL,OnUpdateString,name,zend_inis_globals,inis_globals) + STD_PHP_INI_ENTRY("inis.level","1",PHP_INI_ALL,OnUpdateLong,level,zend_inis_globals,inis_globals) +PHP_INI_END() +``` + +初始化函数 + +```c +static void php_inis_init_globals(zend_inis_globals *inis_globals) +{ + inis_globals->name="sunzy.org"; + inis_globals->level=10; +} +``` + +注册&清除INI变量 + +```c +PHP_MINIT_FUNCTION(inis) +{ + REGISTER_INI_ENTRIES(); + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(inis) +{ + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} +``` + +自定义函数 + +```c +PHP_FUNCTION(inis_report) +{ + php_printf("Name:%s\n",INIS_G(name)); + php_printf("Level:%d\n",INIS_G(level)); +} +``` + +注册自定义函数 + +```c +const zend_function_entry inis_functions[] = { + PHP_FE(inis_report,NULL) + PHP_FE_END /* Must be the last line in inis_functions[] */ +}; +``` + ++ 测试 + +测试脚本 + +```php +$function = "inis_report"; +call_user_func($function); +``` + +测试 + +```shell +$ /usr/local/php5.6.9/bin/php -q inis.php +Functions available in the test extension: +inis_report +Name:sunzy +Level:1 +``` + +修改php.ini + +``` +inis.name=test +inis.level=2 +``` + +```shell +$ /usr/local/php5.6.9/bin/php -q inis.php +Functions available in the test extension: +inis_report +Name:test +Level:2 +``` + + +## 相关的宏 + ++ ZEND_DECLARE_MODULE_GLOBALS ->Zend/zend_API.h + + +```c +#ifdef ZTS +#define ZEND_DECLARE_MODULE_GLOBALS(module_name) \ + ts_rsrc_id module_name##_globals_id; +#else +#define ZEND_DECLARE_MODULE_GLOBALS(module_name) \ + zend_##module_name##_globals module_name##_globals; +#endif +``` + +```ts_rsrc_id```是[线程安全](http://walu.cc/phpbook/1.4.md)里的内容 + ++ PHP_INI_BEGIN、PHP_INI_END、STD_PHP_INI_ENTRY ->main/php_ini.h + +```c +#define PHP_INI_BEGIN ZEND_INI_BEGIN +#define PHP_INI_END ZEND_INI_END +#define STD_PHP_INI_ENTRY STD_ZEND_INI_ENTRY +``` + ++ ZEND_INI_BEGIN、ZEND_INI_END、STD_ZEND_INI_ENTRY -> Zend/zend_ini.h + +```c +#define ZEND_INI_BEGIN() static const zend_ini_entry ini_entries[] = { +#define ZEND_INI_END() { 0, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL } }; + +#define ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, arg1, arg2, arg3, displayer) \ { 0, modifiable, name, sizeof(name), on_modify, arg1, arg2, arg3, default_value, sizeof(default_value)-1, NULL, 0, 0, 0, displayer }, - - #define ZEND_INI_BEGIN() static const zend_ini_entry ini_entries[] = { - #define ZEND_INI_END() { 0, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL } }; - - //注册ini变量,在minit中调用 - #define REGISTER_INI_ENTRIES() zend_register_ini_entries(ini_entries, module_number TSRMLS_CC) - - //清除ini变量,在mshutdown中调用 - #define UNREGISTER_INI_ENTRIES() zend_unregister_ini_entries(module_number TSRMLS_CC) - - //在phpinfo中显示变量值,在minfo中调用 - #define DISPLAY_INI_ENTRIES() display_ini_entries(zend_module) - - // - -3,定义ini变量 - - struct _zend_ini_entry { - int module_number; - int modifiable; - char *name; - uint name_length; - ZEND_INI_MH((*on_modify)); - void *mh_arg1; - void *mh_arg2; - void *mh_arg3; - - char *value; - uint value_length; - - char *orig_value; - uint orig_value_length; - int orig_modifiable; - int modified; - - void (*displayer)(zend_ini_entry *ini_entry, int type); - }; - - //第二个参数即为ini变量的初始值 - PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("inis.enable", "1", PHP_INI_ALL, OnUpdateBool, enable, zend_inis_globals, inis_globals) - STD_PHP_INI_ENTRY("inis.name", "", PHP_INI_ALL, OnUpdateString, name, zend_inis_globals, inis_globals) - STD_PHP_INI_ENTRY("inis.level", "0", PHP_INI_ALL, OnUpdateLong, level, zend_inis_globals, inis_globals) - PHP_INI_END() - - #展开后 - - static const zend_ini_entry ini_entries[] = {//BEGIN - {0, PHP_INI_ALL, "inis.enable", sizeof("inis.enable"), OnUpdateBool, enable, zend_inis_globals, inis_globals... }//inis.enable定义 - ... - { 0, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL } //END - }; - - /*初始化ini值的宏*/ - ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor) - - #module_name 与传递给ZEND_BEGIN_MODULE_GLOBALS()宏相同的扩展名称。 - #globals_ctor 构造函数指针。在myfile扩展里,函数原形与void php_myfile_init_globals(zend_myfile_globals *myfile_globals)类似 - #globals_dtor 析构函数指针。例如,php_myfile_init_globals(zend_myfile_globals *myfile_globals) - -4,注册/清除/显示 ini变量 - PHP_MINIT_FUNCTION(inis) - { - REGISTER_INI_ENTRIES(); - return SUCCESS; - } - - PHP_MSHUTDOWN_FUNCTION(inis) - { - UNREGISTER_INI_ENTRIES(); - return SUCCESS; - } - - PHP_MINFO_FUNCTION(inis) - { - php_info_print_table_start(); - php_info_print_table_header(2, "inis support", "enabled"); - php_info_print_table_end(); - - DISPLAY_INI_ENTRIES(); - } - -5,获取ini变量的值 +#define ZEND_INI_ENTRY3(name, default_value, modifiable, on_modify, arg1, arg2, arg3) \ + ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, arg1, arg2, arg3, NULL) - //INIS_G宏即是用于获取ini变量的值的方法 - PHP_FUNCTION(inis_report) { - php_printf("Name:%s\n", INIS_G(name)); - php_printf("Level:%d\n", INIS_G(level)); - } - - -6,修改ini变量 - - #编辑php.ini文件 - vi /etc/php/php.ini - - #添加动态库,并修改其默认值 - extension=inis.so - inis.name = leon123 - inis.level = 200 +#define ZEND_INI_ENTRY2_EX(name, default_value, modifiable, on_modify, arg1, arg2, displayer) \ + ZEND_INI_ENTRY3_EX(name, default_value, modifiable, on_modify, arg1, arg2, NULL, displayer) + +#define ZEND_INI_ENTRY2(name, default_value, modifiable, on_modify, arg1, arg2) \ + ZEND_INI_ENTRY2_EX(name, default_value, modifiable, on_modify, arg1, arg2, NULL) - #运行,ini变量的值变成为上面修改过的值 - kentchentekiiMac-23868:inis kentchen$ php -q inis.php - Functions available in the test extension: - inis_report - Name:leon123 - Level:200 +#ifdef ZTS +#define STD_ZEND_INI_ENTRY(name, default_value, modifiable, on_modify, property_name, struct_type, struct_ptr) \ + ZEND_INI_ENTRY2(name, default_value, modifiable, on_modify, (void *) XtOffsetOf(struct_type, property_name), (void *) &struct_ptr##_id) +#else +#define STD_ZEND_INI_ENTRY(name, default_value, modifiable, on_modify, property_name, struct_type, struct_ptr) \ + ZEND_INI_ENTRY2(name, default_value, modifiable, on_modify, (void *) XtOffsetOf(struct_type, property_name), (void *) &struct_ptr) +#endif + +``` + +前面扩展中对ini变量的定义展开后 + +```c +static const zend_ini_entry ini_entries[] = {//BEGIN + {0, PHP_INI_ALL, "inis.enable", sizeof("inis.enable"), OnUpdateBool, enable, zend_inis_globals, inis_globals... }//inis.enable定义 + ... + { 0, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL } //END +}; +``` + ++ REGISTER_INI_ENTRIES、UNREGISTER_INI_ENTRIES ->Zend/zend_ini.h + +```c +#define REGISTER_INI_ENTRIES() zend_register_ini_entries(ini_entries, module_number TSRMLS_CC) //注册ini变量 +#define UNREGISTER_INI_ENTRIES() zend_unregister_ini_entries(module_number TSRMLS_CC) //清除ini变量 +#define DISPLAY_INI_ENTRIES() display_ini_entries(zend_module) //在phpinfo中显示变量值 +``` + + ++ ZEND_INIT_MODULE_GLOBALS ->Zend/zend_ini.h + +```c +#ifdef ZTS +#define ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor) \ + ts_allocate_id(&module_name##_globals_id, sizeof(zend_##module_name##_globals), (ts_allocate_ctor) globals_ctor, (ts_allocate_dtor) globals_dtor); +#else +#define ZEND_INIT_MODULE_GLOBALS(module_name, globals_ctor, globals_dtor) \ + globals_ctor(&module_name##_globals); +#endif +``` +初始化ini值的宏 + +> module_name 与传递给ZEND_BEGIN_MODULE_GLOBALS()宏相同的扩展名称。 + +> globals_ctor 构造函数指针。在myfile扩展里,函数原形与void php_myfile_init_globals(zend_myfile_globals *myfile_globals)类似 + +> globals_dtor 析构函数指针。例如,php_myfile_init_globals(zend_myfile_globals *myfile_globals) - #注释php.ini里设置值的语句,ini变量值变回了默认值 - kentchentekiiMac-23868:inis kentchen$ php -q inis.php - Functions available in the test extension: - inis_report - Name:leon peng - Level:100 diff --git a/05.md b/05.md index d582990..8353a65 100644 --- a/05.md +++ b/05.md @@ -2,178 +2,189 @@ 1,创建一个扩展 - ./ext_skel --extname=array - +```shell +./ext_skel --extname=array +``` + 2,hashTable函数说明 - - typedef struct bucket { - ulong h; /* Used for numeric indexing */ - uint nKeyLength; - void *pData; - void *pDataPtr; - struct bucket *pListNext; - struct bucket *pListLast; - struct bucket *pNext; - struct bucket *pLast; - const char *arKey; - } Bucket; - - typedef struct _hashtable { - uint nTableSize; - uint nTableMask; - uint nNumOfElements; - ulong nNextFreeElement; - Bucket *pInternalPointer; /* Used for element traversal */ - Bucket *pListHead; - Bucket *pListTail; - Bucket **arBuckets; - dtor_func_t pDestructor; - zend_bool persistent; - unsigned char nApplyCount; - zend_bool bApplyProtection; - #if ZEND_DEBUG - int inconsistent; - #endif - } HashTable; - - typedef Bucket* HashPosition; - - - //初始化HashTable - HashTable *myht; - zval *zv; - - /* Same as myht = emalloc(sizeof(HashTable)); */ - ALLOC_HASHTABLE(myht); - - zend_hash_init(myht, 0, NULL, ZVAL_PTR_DTOR, 0); - MAKE_STD_ZVAL(zv); - ZVAL_STRING(zv, "foo", 1); - - /* In PHP: $array[42] = "foo" */ - zend_hash_index_update(myht, 42, &zv, sizeof(zval *), NULL); - zend_hash_destroy(myht); - - /* Same as efree(myht); */ - FREE_HASHTABLE(myht); +```c +typedef struct bucket { + ulong h; /* Used for numeric indexing */ + uint nKeyLength; + void *pData; + void *pDataPtr; + struct bucket *pListNext; + struct bucket *pListLast; + struct bucket *pNext; + struct bucket *pLast; + const char *arKey; +} Bucket; +typedef struct _hashtable { + uint nTableSize; + uint nTableMask; + uint nNumOfElements; + ulong nNextFreeElement; + Bucket *pInternalPointer; /* Used for element traversal */ + Bucket *pListHead; + Bucket *pListTail; + Bucket **arBuckets; + dtor_func_t pDestructor; + zend_bool persistent; + unsigned char nApplyCount; + zend_bool bApplyProtection; + #if ZEND_DEBUG + int inconsistent; + #endif +} HashTable; - HashTable *names, *options = NULL; - HashPosition pos;//此值是Bucket的指针,pos->h表示的即是当前值的index - zval **val; - zend_bool key_exist; - - //基于string key的操作函数 - - key_exist = zend_hash_exists(options, "key", sizeof("key")); //在hashtable中查找key,如果查到则返回true,只针对于"key" => "value"这样的数组 - zend_hash_find(options, "hello", sizeof("hello"), (void **)&val) == SUCCESS; //在options中查找hello,如果找到则返回SUCCESS - - char *k1 = "key1"; - zval *v1; - MAKE_STD_ZVAL(v1); - ZVAL_STRING(v1, "value1", 1); - zend_hash_add(names, k1, sizeof(k1), &v1, sizeof(zval *), NULL); //为添加hashtable添加一个新的元素, 即 "key1" => "value1" - - zend_hash_update(names, "name", sizeof("name"), &v2, sizeof(zval *), NULL);//按key更新hashtable元素的值 - - zend_hash_del(names, k1, sizeof(k1));//按key删除一个元素 - - //基于long key的操作函数 +typedef Bucket* HashPosition; + + +//初始化HashTable +HashTable *myht; +zval *zv; + +/* Same as myht = emalloc(sizeof(HashTable)); */ +ALLOC_HASHTABLE(myht); + +zend_hash_init(myht, 0, NULL, ZVAL_PTR_DTOR, 0); +MAKE_STD_ZVAL(zv); +ZVAL_STRING(zv, "foo", 1); + +/* In PHP: $array[42] = "foo" */ +zend_hash_index_update(myht, 42, &zv, sizeof(zval *), NULL); + +zend_hash_destroy(myht); + +/* Same as efree(myht); */ +FREE_HASHTABLE(myht); + + +HashTable *names, *options = NULL; +HashPosition pos;//此值是Bucket的指针,pos->h表示的即是当前值的index +zval **val; +zend_bool key_exist; + +//基于string key的操作函数 + +key_exist = zend_hash_exists(options, "key", sizeof("key")); +//在hashtable中查找key,如果查到则返回true,只针对于"key" => "value"这样的数组 +zend_hash_find(options, "hello", sizeof("hello"), (void **)&val) == SUCCESS; +//在options中查找hello,如果找到则返回SUCCESS + +char *k1 = "key1"; +zval *v1; +MAKE_STD_ZVAL(v1); +ZVAL_STRING(v1, "value1", 1); +zend_hash_add(names, k1, sizeof(k1), &v1, sizeof(zval *), NULL); //为添加hashtable添加一个新的元素, 即 "key1" => "value1" + +zend_hash_update(names, "name", sizeof("name"), &v2, sizeof(zval *), NULL);//按key更新hashtable元素的值 + +zend_hash_del(names, k1, sizeof(k1));//按key删除一个元素 - zval *v3; - MAKE_STD_ZVAL(v3); - ZVAL_STRING(v3, "value3", 1); - zend_hash_index_update(names, 0, &v3, sizeof(zval *), NULL);//按数字索引键更新HashTable元素的值 - - zval **v4; - zend_hash_index_find(names, 1, &v4); //按数字索引获取HashTable元素的值 - php_printf("v4 : "); - PHPWRITE(Z_STRVAL_PP(v4), Z_STRLEN_PP(v4)); - php_printf("\n"); +//基于long key的操作函数 - ulong idx; - idx = zend_hash_index_exists(names, 10);//按数字索引查找HashTable,如果找到返回 1, 反之则返回 0 +zval *v3; +MAKE_STD_ZVAL(v3); +ZVAL_STRING(v3, "value3", 1); +zend_hash_index_update(names, 0, &v3, sizeof(zval *), NULL);//按数字索引键更新HashTable元素的值 - zend_hash_index_del(names, 2); //按数字索引删除HashTable元素 - - - //hashTable的遍历函数 - - zend_hash_internal_pointer_reset(names); //初始化hash指针 - zend_hash_internal_pointer_reset_ex(names, &pos);//初始化hash指针,并付值给pos - - zend_hash_get_current_data(names, (void**) &val); //获取当前hash存储值,data should be cast to void**, ie: (void**) &data - zend_hash_get_current_data_ex(names, (void**) &val, &pos) == SUCCESS; //获取当前hash存储值 - - zend_hash_get_current_key(names, &key, &klen, &index, 0) == HASH_KEY_IS_LONG - zend_hash_get_current_key_ex(names, &key, &klen, &index, 0, &pos) == HASH_KEY_IS_LONG; //读取hashtable当前的KEY,返回值会有两种 HASH_KEY_IS_LONG | HASH_KEY_IS_STRING ,分别对应array("value"),array("key"=>"value")两种hashtable - - zend_hash_move_forward(names); - zend_hash_move_forward_ex(names, &pos); //hash指针移至下一位 +zval **v4; +zend_hash_index_find(names, 1, &v4); //按数字索引获取HashTable元素的值 +php_printf("v4 : "); +PHPWRITE(Z_STRVAL_PP(v4), Z_STRLEN_PP(v4)); +php_printf("\n"); + +ulong idx; +idx = zend_hash_index_exists(names, 10);//按数字索引查找HashTable,如果找到返回 1, 反之则返回 0 + +zend_hash_index_del(names, 2); //按数字索引删除HashTable元素 + + +//hashTable的遍历函数 - //HashTable长度 - php_printf("%*carray(%d) {\n", depth * 2, ' ', zend_hash_num_elements(Z_ARRVAL_P(zv)) +zend_hash_internal_pointer_reset(names); //初始化hash指针 +zend_hash_internal_pointer_reset_ex(names, &pos);//初始化hash指针,并付值给pos + +zend_hash_get_current_data(names, (void**) &val); //获取当前hash存储值,data should be cast to void**, ie: (void**) &data +zend_hash_get_current_data_ex(names, (void**) &val, &pos) == SUCCESS; //获取当前hash存储值 + +zend_hash_get_current_key(names, &key, &klen, &index, 0) == HASH_KEY_IS_LONG +zend_hash_get_current_key_ex(names, &key, &klen, &index, 0, &pos) == HASH_KEY_IS_LONG; //读取hashtable当前的KEY,返回值会有两种 HASH_KEY_IS_LONG | HASH_KEY_IS_STRING ,分别对应array("value"),array("key"=>"value")两种hashtable +zend_hash_move_forward(names); +zend_hash_move_forward_ex(names, &pos); //hash指针移至下一位 + +//HashTable长度 +php_printf("%*carray(%d) {\n", depth * 2, ' ', zend_hash_num_elements(Z_ARRVAL_P(zv)) +``` 3,数组函数说明 1)Zend's API for Associative Arrays - - zval *arr; - MAKE_STD_ZVAL(arr); - - array_init(arr); //$arr = array(); - add_assoc_long(arr, "a", 10); //$arr["a"] = 10; - add_asoc_unset(arr, "a"); //unset(arr["a"]); - add_assoc_bool(arr, "b", 1); //$arr["b"] = true; - add_assoc_resource(arr, "c", 10); //$arr["c"] = $resource; - add_assoc_double(arr, "d", 2.15); //$arr["d"] = 2.15; - add_assoc_string(arr, "e", "hello", 1); //$arr["e"] = "hello";最后一个参数表示字符串值是否复制 - add_assoc_stringl(); - - zval *sub; - MAKE_STD_ZVAL(sub); - array_init(sub); - add_assoc_zval(arr, "f", sub); //$arr["f"] = $sub; - + +```c +zval *arr; +MAKE_STD_ZVAL(arr); + +array_init(arr); //$arr = array(); +add_assoc_long(arr, "a", 10); //$arr["a"] = 10; +add_asoc_unset(arr, "a"); //unset(arr["a"]); +add_assoc_bool(arr, "b", 1); //$arr["b"] = true; +add_assoc_resource(arr, "c", 10); //$arr["c"] = $resource; +add_assoc_double(arr, "d", 2.15); //$arr["d"] = 2.15; +add_assoc_string(arr, "e", "hello", 1); //$arr["e"] = "hello";最后一个参数表示字符串值是否复制 +add_assoc_stringl(); + +zval *sub; +MAKE_STD_ZVAL(sub); +array_init(sub); +add_assoc_zval(arr, "f", sub); //$arr["f"] = $sub; +``` + 2)Zend's API for Indexed Arrays, Part 1 - - zval *arr; - MAKE_STD_ZVAL(arr); - - array_init(arr); //$arr = array(); - add_index_long(arr, 1, 10); //$arr[1] = 10; - add_index_unset(arr, 1); //unset($arr[1]); - add_index_bool(arr, 2, 1); //$arr[2] = true; - add_index_resource(arr, 3, 10); //$arr[3] = $resource; - add_index_double(arr, 4, 2.15); //$arr[4] = 2.15; - add_index_string(arr, 5, "hello", 1); //$arr[5] = "hello";最后一个参数表示字符串值是否复制 - add_index_stringl(); - - zval *sub; - MAKE_STD_ZVAL(sub); - array_init(sub); - add_index_zval(arr, 6, sub); //$arr[6] = $sub; - + +```c +zval *arr; +MAKE_STD_ZVAL(arr); + +array_init(arr); //$arr = array(); +add_index_long(arr, 1, 10); //$arr[1] = 10; +add_index_unset(arr, 1); //unset($arr[1]); +add_index_bool(arr, 2, 1); //$arr[2] = true; +add_index_resource(arr, 3, 10); //$arr[3] = $resource; +add_index_double(arr, 4, 2.15); //$arr[4] = 2.15; +add_index_string(arr, 5, "hello", 1); //$arr[5] = "hello";最后一个参数表示字符串值是否复制 +add_index_stringl(); + +zval *sub; +MAKE_STD_ZVAL(sub); +array_init(sub); +add_index_zval(arr, 6, sub); //$arr[6] = $sub; +``` + 3)Zend's API for Indexed Arrays, Part 2 - - zval *arr; - MAKE_STD_ZVAL(arr); - - array_init(arr); //$arr = array(); - add_next_index_long(arr, 10); //$arr[] = 10; - add_next_index_unset(arr); //unset($arr[]); - add_next_index_bool(arr, 1); //$arr[] = true; - add_next_index_resource(arr, 10); //$arr[] = $resource; - add_next_index_double(arr, 2.15); //$arr[] = 2.15; - add_next_index_string(arr, "hello", 1); //$arr[] = "hello";最后一个参数表示字符串值是否复制 - add_next_index_stringl(); - - zval *sub; - MAKE_STD_ZVAL(sub); - array_init(sub); - add_next_index_zval(arr, sub); //$arr[] = $sub; + +```c +zval *arr; +MAKE_STD_ZVAL(arr); + +array_init(arr); //$arr = array(); +add_next_index_long(arr, 10); //$arr[] = 10; +add_next_index_unset(arr); //unset($arr[]); +add_next_index_bool(arr, 1); //$arr[] = true; +add_next_index_resource(arr, 10); //$arr[] = $resource; +add_next_index_double(arr, 2.15); //$arr[] = 2.15; +add_next_index_string(arr, "hello", 1); //$arr[] = "hello";最后一个参数表示字符串值是否复制 +add_next_index_stringl(); + +zval *sub; +MAKE_STD_ZVAL(sub); +array_init(sub); +add_next_index_zval(arr, sub); //$arr[] = $sub; +``` diff --git a/14.md b/14.md new file mode 100644 index 0000000..abc68dc --- /dev/null +++ b/14.md @@ -0,0 +1,137 @@ +# output操作 + +1,创建一个新的扩展 + + ./ext_skel --extname=output1 + +2,修改config.m4,去掉没用的注释语句 + + cd output1 + vi config.m4 + +3,编写代码 + + vi output1.c + #修改confirm_output_compiled + PHP_FUNCTION(confirm_output_compiled) + { + char *arg = NULL; + int arg_len, len; + char *strg; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { + return; + } + + FILE *fp = NULL; + long fsize; + char *buffer; + size_t result; + + fp = fopen(arg, "r"); + if (fp == NULL) { + RETURN_FALSE; + } + + fseek(fp, 0, SEEK_END); + fsize = ftell(fp); + rewind(fp); + buffer = (char *)malloc(sizeof(char) * fsize); + result = fread(buffer, 1, fsize, fp); + fclose(fp); + + //输出Content-type + char *content_type = "'Content-type: image/jpeg"; + sapi_header_line ctr = {0}; + ctr.line = content_type; + ctr.line_len = strlen(content_type); + ctr.response_code = 200; + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); + + //输出图像 + php_output_write(buffer, result TSRMLS_CC); + php_output_end_all(TSRMLS_C); + + + free(buffer); + + RETURN_TRUE; + } + +4,结构 + + //1, 输出header操作 + // SAPI.h + typedef struct { + char *line; //输出的内容,记得需要自已释放内存 + uint line_len; //输出内容的长度 + long response_code; //状态码 + } sapi_header_line; + + typedef enum { /* Parameter: */ + SAPI_HEADER_REPLACE, /* sapi_header_line* */ + SAPI_HEADER_ADD, /* sapi_header_line* */ + SAPI_HEADER_DELETE, /* sapi_header_line* */ + SAPI_HEADER_DELETE_ALL, /* void */ + SAPI_HEADER_SET_STATUS /* int */ + } sapi_header_op_enum; + + #调用sapi_header_op输出内容 + char *content_type = "'Content-type: image/jpeg"; + sapi_header_line ctr = {0}; + ctr.line = content_type; + ctr.line_len = strlen(content_type); + ctr.response_code = 200; + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); + + //2, 输出内容操作 + //main/php_output.h + + ZEND_BEGIN_MODULE_GLOBALS(output) + int flags; + zend_stack handlers; + php_output_handler *active; + php_output_handler *running; + const char *output_start_filename; + int output_start_lineno; + ZEND_END_MODULE_GLOBALS(output) + + #define PHP_OUTPUT_IMPLICITFLUSH 0x01 + #define PHP_OUTPUT_DISABLED 0x02 //当flags=PHP_OUTPUT_DISABLED时,则会禁止输出 + #define PHP_OUTPUT_WRITTEN 0x04 + #define PHP_OUTPUT_SENT 0x08 + #define PHP_OUTPUT_ACTIVE 0x10 + #define PHP_OUTPUT_LOCKED 0x20 + + #define PHP_OUTPUT_ACTIVATED 0x100000 + //当flags=PHP_OUTPUT_ACTIVATED,会调用sapi_module.ub_write输出, 每个SAPI都有自已的实现, cli中是调用sapi_cli_single_write() + + php_output_write(); //输出,有buffer, 调用php_output_op() + php_output_write_unbuffered();//输出,没有buffer,调用PHP_OUTPUT_ACTIVATED,会调用sapi_module.ub_write + php_output_set_status(); //用于SAPI设置output.flags , + php_output_get_status(); //获取output.flags的值 + + php_output_op();// +5,宏 + + #define PHPWRITE(str, str_len) php_output_write((str), (str_len) TSRMLS_CC) + #define PHPWRITE_H(str, str_len) php_output_write_unbuffered((str), (str_len) TSRMLS_CC) + + #define PUTC(c) (php_output_write(&(c), 1 TSRMLS_CC), (c)) + #define PUTC_H(c) (php_output_write_unbuffered(&(c), 1 TSRMLS_CC), (c)) + + #define PUTS(str) do { \ + const char *__str = (str); \ + php_output_write(__str, strlen(__str) TSRMLS_CC); \ + } while (0) + #define PUTS_H(str) do { \ + const char *__str = (str); \ + php_output_write_unbuffered(__str, strlen(__str) TSRMLS_CC); \ + } while (0) + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index e34063a..e33243e 100644 --- a/README.md +++ b/README.md @@ -2,39 +2,43 @@ #### 目录 -[1,创建一个新的扩展](https://github.com/Leon2012/php-ext/blob/master/01.md) +[1,创建一个新的扩展](./01.md) -[2,参数传递](https://github.com/Leon2012/php-ext/blob/master/02.md) +[2,参数传递](./02.md) -[3,返回值](https://github.com/Leon2012/php-ext/blob/master/03.md) +[3,返回值](./03.md) -[4,INI参数设置](https://github.com/Leon2012/php-ext/blob/master/04.md) +[4,INI参数设置](./04.md) -[5,数组](https://github.com/Leon2012/php-ext/blob/master/05.md) +[5,数组](./05.md) -[6,Global变量](https://github.com/Leon2012/php-ext/blob/master/06.md) +[6,Global变量](./06.md) -[7,常量](https://github.com/Leon2012/php-ext/blob/master/07.md) +[7,常量](./07.md) -[8,调用php函数](https://github.com/Leon2012/php-ext/blob/master/08.md) +[8,调用php函数](./08.md) -[9,类与对像1](https://github.com/Leon2012/php-ext/blob/master/09.md) +[9,类与对象1](./09.md) -[10,类与对像2(自定义object存储)](https://github.com/Leon2012/php-ext/blob/master/10.md) +[10,类与对象2(自定义object存储)](./10.md) -[11,类与对像3(object handlers)](https://github.com/Leon2012/php-ext/blob/master/11.md) +[11,类与对象3(object handlers)](./11.md) -[12,资源](https://github.com/Leon2012/php-ext/blob/master/12.md) +[12,资源](./12.md) -[13,包装第三方库](https://github.com/Leon2012/php-ext/blob/master/13.md) +[13,包装第三方库](./13.md) + +[14,output操作](./14.md) #### 附录 -[1,gdb调试PHP扩展函数](https://github.com/Leon2012/php-ext/blob/master/001.md) +[1,gdb调试PHP扩展函数](./001.md) + +[2,常用全局宏](./002.md) -[2,常用全局宏](https://github.com/Leon2012/php-ext/blob/master/002.md) +[3,zval](./003.md) -[3,zval](https://github.com/Leon2012/php-ext/blob/master/003.md) +[4,ZendMM](./004.md) ##### 参考 @@ -42,4 +46,6 @@ [http://www.walu.cc/phpbook/](http://www.walu.cc/phpbook/) +[https://wikitech.wikimedia.org/wiki/GDB_with_PHP](https://wikitech.wikimedia.org/wiki/GDB_with_PHP) +